React 能够直接下载使用,下载包中也提供了不少学习的实例。css
本教程使用了 React 的版本为 16.4.0,你能够在官网 https://reactjs.org/ 下载最新版。html
你也能够直接使用 Staticfile CDN 的 React CDN 库,地址以下:react
<!-- 生产环境中不建议使用 -->webpack
官方提供的 CDN 地址:git
<!-- 生产环境中不建议使用 -->github
NPM管理web
npm install --save react react-dom babelify babel-preset-react
npm install --save babel-preset-es2015
使用webpack打包配置
全局安装webpack
npm install -g webpack
全局安装完webpack还须要项目下安装npm install webpack --save
全局安装webpack开发服务器
npm install -g webpack-dev-server
全局安装完webpack-dev-server 后还须要在当前目录下安装npm install webpack-dev-server --save
如下实例输出了 Hello, world!npm
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
实例解析:json
实例中咱们引入了三个库: react.min.js 、react-dom.min.js 和 babel.min.js:api
react.min.js - React 的核心库
react-dom.min.js - 提供与 DOM 相关的功能
babel.min.js - Babel 能够将 ES6 代码转为 ES5 代码,这样咱们就能在目前不支持 ES6 浏览器上执行 React 代码。Babel 内嵌了对 JSX 的支持。经过将 Babel 和 babel-sublime 包(package)一同使用可让源码的语法渲染上升到一个全新的水平。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
以上代码将一个 h1 标题,插入 id="example" 节点中。
注意:
若是咱们须要使用 JSX,则 <script> 标签的 type 属性须要设置为 text/babel。
国内使用 npm 速度很慢,你可使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
$ npm config set registry https://registry.npm.taobao.org
这样就可使用 cnpm 命令来安装模块了:
$ cnpm install [name]
create-react-app 是来自于 Facebook,经过该命令咱们无需配置就能快速构建 React 开发环境。
create-react-app 自动建立的项目是基于 Webpack + ES6 。
执行如下命令建立项目:
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start
manifest.json 指定了开始页面 index.html,一切的开始都从这里开始,因此这个是代码执行的源头。
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>欢迎来到hello world</h2>
</div>
<p className="App-intro">
你能够在 <code>src/App.js</code> 文件中修改。
</p>
</div>
);
}
}
export default App;
元素是构成 React 应用的最小单位,它用于描述屏幕上输出的内容。
const element = <h1>Hello, world!</h1>;
首先咱们在一个 HTML 页面中添加一个 id="example" 的 <div>:
<div id="example"></div>
在此 div 中的全部内容都将由 React DOM 来管理,因此咱们将其称之为 "根" DOM 节点。
咱们用 React 开发应用时通常只会定义一个根节点。但若是你是在一个已有的项目当中引入 React 的话,你可能会须要在不一样的部分单独定义 React 根节点。
要将React元素渲染到根DOM节点中,咱们经过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
实例:
const element = <h1>Hello, world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
React 元素都是不可变的。当元素被建立以后,你是没法改变其内容或属性的。
目前更新界面的惟一办法是建立一个新的元素,而后将它传入 ReactDOM.render() 方法:
来看一下这个计时器的例子:
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick, 1000);
以上实例经过 setInterval() 方法,每秒钟调用一次 ReactDOM.render()。
咱们能够将要展现的部分封装起来,如下实例用一个函数来表示:
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
);
}
setInterval(tick, 1000);
除了函数外咱们还能够建立一个 React.Component 的 ES6 类,该类封装了要展现的元素,须要注意的是在 render() 方法中,须要使用 this.props 替换 props:
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
);
}
setInterval(tick, 1000);
React 只会更新必要的部分
值得注意的是 React DOM 首先会比较元素内容前后的不一样,而在渲染过程当中只会更新改变了的部分。
React 使用 JSX 来替代常规的 JavaScript。
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
咱们不须要必定使用 JSX,但它有如下优势:
JSX 执行更快,由于它在编译为 JavaScript 代码后进行了优化。
它是类型安全的,在编译过程当中就能发现错误。
使用 JSX 编写模板更加简单快速。
JSX 看起来相似 HTML ,咱们能够看下实例:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
咱们能够在以上代码中嵌套多个 HTML 标签,须要使用一个 div 元素包裹它,实例中的 p 元素添加了自定义属性 data-myattribute,添加自定义属性须要使用 data- 前缀。
ReactDOM.render(
<div>
<h1>hello world</h1>
<h2>欢迎学习 React</h2>
<p data-myattribute = "somevalue">这是一个很不错的 JavaScript 库!</p>
</div>
,
document.getElementById('example')
);
你的 React JSX 代码能够放在一个独立文件上,例如咱们建立一个 helloworld_react.js
文件,代码以下:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
而后在 HTML 文件中引入该 JS 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel" src="./hellow_react.js"></script>
</body>
</html>
咱们能够在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中。实例以下:
ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
,
document.getElementById('example')
);
在 JSX 中不能使用 if else 语句,但可使用 conditional (三元运算) 表达式来替代。如下实例中若是变量 i 等于 1 浏览器将输出 true, 若是修改 i 的值,则会输出 false.
ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
,
document.getElementById('example')
);
React 推荐使用内联样式。咱们可使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px 。如下实例演示了为 h1 元素添加 myStyle 内联样式:
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>hello world</h1>,
document.getElementById('example')
);
注释须要写在花括号中,实例以下:
ReactDOM.render(
<div>
<h1>hello world</h1>
{/*注释...*/}
</div>,
document.getElementById('example')
);
JSX 容许在模板中插入数组,数组会自动展开全部成员:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var arr = [
<h1>cainiaojiaocheng</h1>,
<h2>是时候展现真正的技术了</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById("example")
)
</script>
</body>
</html>
React 能够渲染 HTML 标签 (strings) 或 React 组件 (classes)。
要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。
var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));
要渲染 React 组件,只需建立一个大写字母开头的本地变量
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement, document.getElementById('example'));
React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。
注意:
因为 JSX 就是 JavaScript,一些标识符像 class
和 for
不建议做为 XML 属性名。做为替代,React DOM 使用 className
和 htmlFor
来作对应的属性。
接下来咱们封装一个输出 "Hello World!" 的组件,组件名为 HelloMessage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
function HelloCompent(params) {
return <h1>hellow amisu</h1>;
}
const element = <HelloCompent/>
ReactDOM.render(
element,
document.getElementById("example")
)
</script>
</body>
</html>
一、咱们可使用函数定义了一个组件:
function HelloMessage(props) {
return <h1>Hello World!</h1>;
}
你也可使用 ES6 class 来定义一个组件:
class Welcome extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
二、const element = <HelloMessage /> 为用户自定义的组件。
注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,好比 HelloMessage 不能写成 helloMessage。除此以外还须要注意组件类只能包含一个顶层标签,不然也会报错。
若是咱们须要向组件传递参数,可使用 this.props 对象,实例以下:
function HelloMessage(props) {
return <h1>Hello {props.name}!</h1>;
}
const element = <HelloMessage name="Runoob"/>;
ReactDOM.render(
element,
document.getElementById('example')
);
以上实例中 name 属性经过 props.name 来获取。
注意,在添加属性时, class 属性须要写成 className ,for 属性须要写成 htmlFor ,这是由于 class 和 for 是 JavaScript 的保留字。
咱们能够经过建立多个组件来合成一个组件,即把组件的不一样功能点进行分离。
如下实例咱们实现了输出网站名字和网址的组件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
function Name(props) {
return <h1>网站名称:{props.name}</h1>;
}
function Url(props) {
return <h1>网站地址:{props.url}</h1>;
}
function App() {
return (
<div>
<Name name="hello world" />
<Url url="http://www.runoob.com" />
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById("example")
)
</script>
</body>
</html>
实例中 App 组件使用了 Name、Url 组件来输出对应的信息。
React 把组件当作是一个状态机(State Machines)。经过与用户的交互,实现不一样状态,而后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,而后根据新的 state 从新渲染用户界面(不要操做 DOM)。
如下实例建立一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。
添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
接下来,咱们将使Clock设置本身的计时器并每秒更新一次。
在具备许多组件的应用程序中,在销毁时释放组件所占用的资源很是重要。
每当 Clock 组件第一次加载到 DOM 中的时候,咱们都想生成定时器,这在 React 中被称为挂载。
一样,每当 Clock 生成的这个 DOM 被移除的时候,咱们也会想要清除定时器,这在 React 中被称为卸载。
咱们能够在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
实例解析:
componentDidMount() 与 componentWillUnmount() 方法被称做生命周期钩子。
在组件输出到 DOM 后会执行 componentDidMount() 钩子,咱们就能够在这个钩子上设置一个定时器。
this.timerID 为计算器的 ID,咱们能够在 componentWillUnmount() 钩子中卸载计算器。
代码执行顺序:
当 <Clock />
被传递给 ReactDOM.render()
时,React 调用 Clock
组件的构造函数。 因为 Clock
须要显示当前时间,因此使用包含当前时间的对象来初始化 this.state
。 咱们稍后会更新此状态。
React 而后调用 Clock
组件的 render()
方法。这是 React 了解屏幕上应该显示什么内容,而后 React 更新 DOM 以匹配 Clock
的渲染输出。
当 Clock
的输出插入到 DOM 中时,React 调用 componentDidMount()
生命周期钩子。 在其中,Clock
组件要求浏览器设置一个定时器,每秒钟调用一次 tick()
。
浏览器每秒钟调用 tick()
方法。 在其中,Clock
组件经过使用包含当前时间的对象调用 setState()
来调度UI更新。 经过调用 setState()
,React 知道状态已经改变,并再次调用 render()
方法来肯定屏幕上应当显示什么。 这一次,render()
方法中的 this.state.date
将不一样,因此渲染输出将包含更新的时间,并相应地更新 DOM。
一旦 Clock
组件被从 DOM 中移除,React 会调用 componentWillUnmount()
这个钩子函数,定时器也就会被清除。
父组件或子组件都不能知道某个组件是有状态仍是无状态,而且它们不该该关心某组件是被定义为一个函数仍是一个类。
这就是为何状态一般被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
如下实例中 FormattedDate 组件将在其属性中接收到 date 值,而且不知道它是来自 Clock 状态、仍是来自 Clock 的属性、亦或手工输入:
为了代表全部组件都是真正隔离的,咱们能够建立一个 App 组件,它渲染三个Clock:
function FormattedDate(props) {
return <h2>如今是 {props.date.toLocaleTimeString()}.</h2>;
}
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<FormattedDate date={this.state.date} />
</div>
);
}
}
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('example'));
以上实例中每一个 Clock 组件都创建了本身的定时器而且独立更新。
在 React 应用程序中,组件是有状态仍是无状态被认为是可能随时间而变化的组件的实现细节。
咱们能够在有状态组件中使用无状态组件,也能够在无状态组件中使用有状态组件。
state 和 props 主要的区别在于 props 是不可变的,而 state 能够根据与用户交互来改变。这就是为何有些容器组件须要定义 state 来更新和修改数据。 而子组件只能经过 props 来传递数据。
function HelloMessage(props) { return <h1>Hello {props.name}!</h1>; } const element = <HelloMessage name="Runoob"/>; ReactDOM.render( element, document.getElementById('example') );
你能够经过组件类的 defaultProps 属性为 props 设置默认值,实例以下:
class HelloMessage extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } HelloMessage.defaultProps = { name: 'Runoob' }; const element = <HelloMessage/>; ReactDOM.render( element, document.getElementById('example') );
如下实例演示了如何在应用中组合使用 state 和 props 。咱们能够在父组件中设置 state, 并经过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 咱们设置 name 和 site 来获取父组件传递过来的数据。
class WebSite extends React.Component { constructor() { super(); this.state = { name: "hello world", site: "https://www.runoob.com" } } render() { return ( <div> <Name name={this.state.name} /> <Link site={this.state.site} /> </div> ); } } class Name extends React.Component { render() { return ( //ES6方法接收参数用的是this.props.xxx,函数式直接props.xx <h1>{this.props.name}</h1> ); } } class Link extends React.Component { render() { return ( <a href={this.props.site}> {this.props.site} </a> ); } } ReactDOM.render( <WebSite />, document.getElementById('example') );
React 元素的事件处理和 DOM 元素相似。可是有一点语法上的不一样:
React 事件绑定属性的命名采用驼峰式写法,而不是小写。
若是采用 JSX 的语法你须要传入一个函数做为事件处理函数,而不是一个字符串(DOM 元素的写法)
HTML 一般写法是:
<button onclick="activateLasers()"> 激活按钮 </button>
React 中写法为:
<button onClick={activateLasers}> 激活按钮 </button>
在 React 中另外一个不一样是你不能使用返回 false 的方式阻止默认行为, 你必须明确的使用 preventDefault。
<a href="#" onclick="console.log('点击连接'); return false"> 点我 </a>
在 React 的写法为:
function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('连接被点击'); } return ( <a href="#" onClick={handleClick}> 点我 </a> ); }
实例中 e 是一个合成事件。
使用 React 的时候一般你不须要使用 addEventListener 为一个已建立的 DOM 元素添加监听器。你仅仅须要在这个元素初始渲染的时候提供一个监听器。
当你使用 ES6 class 语法来定义一个组件的时候,事件处理器会成为类的一个方法。例如,下面的 Toggle 组件渲染一个让用户切换开关状态的按钮:
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // 这边绑定是必要的,这样 `this` 才能在回调函数中使用 this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('example') );
你必须谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的。若是你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined。
这并非 React 的特殊行为;它是函数如何在 JavaScript 中运行的一部分。一般状况下,若是你没有在方法后面添加 () ,例如 onClick={this.handleClick},你应该为这个方法绑定 this。
若是使用 bind 让你很烦,这里有两种方式能够解决。若是你正在使用实验性的属性初始化器语法,你可使用属性初始化器来正确的绑定回调函数:
class LoggingButton extends React.Component { // 这个语法确保了 `this` 绑定在 handleClick 中 // 这里只是一个测试 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
若是你没有使用属性初始化器语法,你能够在回调函数中使用 箭头函数:
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // 这个语法确保了 `this` 绑定在 handleClick 中 return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
使用这个语法有个问题就是每次 LoggingButton 渲染的时候都会建立一个不一样的回调函数。在大多数状况下,这没有问题。然而若是这个回调函数做为一个属性值传入低阶组件,这些组件可能会进行额外的从新渲染。咱们一般建议在构造函数中绑定或使用属性初始化器语法来避免这类性能问题。
一般咱们会为事件处理程序传递额外的参数。例如,如果 id 是你要删除那一行的 id,如下两种方式均可以向事件处理程序传递参数:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上述两种方式是等价的。
上面两个例子中,参数 e 做为 React 事件对象将会被做为第二个参数进行传递。经过箭头函数的方式,事件对象必须显式的进行传递,可是经过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。
值得注意的是,经过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面,例如:
class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //事件对象e要放在最后 e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/* 经过 bind() 方法传递参数。 */} <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a> </div> ); } }
在React中,你能够建立不一样的组件来封装各类需求行为,而后还能够根据应用的状态变化只渲染其中的一部分。而后还能够根据应用的状态变化只渲染其中的一部分。
先来看两个组件:
function UserGreeting(props) { return <h1>欢迎回来!</h1>; } function GuestGreeting(props) { return <h1>请先注册。</h1>; }
咱们将建立一个 Greeting 组件,它会根据用户是否登陆来显示其中之一:
function Greeting(props) { const isLoginIn = props.isLoginIn ; if(isLoginIn){ return <GuestGreeting /> } return <GuestGreeting/> } ReactDOM.render( //尝试修改 isLoginIn={true}; <Greeting isLoginIn={false}/> document.getElementById("example") )
你可使用变量来储存元素。它能够帮助你有条件的渲染组件的一部分,而输出的其余部分不会更改。
在下面的例子中,咱们将要建立一个名为 LoginControl 的有状态的组件。
它会根据当前的状态来渲染 <LoginButton /> 或 <LogoutButton />,它也将渲染前面例子中的 <Greeting />。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class LoginControl extends React.Component { constructor(props) { super(props); this.handleLoginClick = this.handleLoginClick.bind(this); this.handleLogoutClick = this.handleLogoutClick.bind(this); this.state = {isLoggedIn: false}; } handleLoginClick() { this.setState({isLoggedIn: true}); } handleLogoutClick() { this.setState({isLoggedIn: false}); } render() { const isLoggedIn = this.state.isLoggedIn; let button; if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; } return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div> ); } } function UserGreeting(props) { return <h1>欢迎回来!</h1>; } function GuestGreeting(props) { return <h1>请先注册。</h1>; } function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; } function LoginButton(props) { return ( <button onClick={props.onClick}> 登录 </button> ); } function LogoutButton(props) { return ( <button onClick={props.onClick}> 退出 </button> ); } ReactDOM.render( <LoginControl />, document.getElementById('example') ); </script> </body> </html>
你能够经过用花括号包裹代码在 JSX 中嵌入任何表达式 ,也包括 JavaScript 的逻辑与 &&,它能够方便地条件渲染一个元素。
function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> 您有 {unreadMessages.length} 条未读信息。 </h2> } </div> ); } const messages = ['React', 'Re: React', 'Re:Re: React']; ReactDOM.render( <Mailbox unreadMessages={messages} />, document.getElementById('example') );
条件渲染的另外一种方法是使用 JavaScript 的条件运算符:condition ? true : false。
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <style> button { height: 40px; width: 200px; } .warning { background-color: red; text-align: center; width: 100%; padding: 10px; font-size: 14pt; color: white; } </style> </head> <body> <div id="example"></div> <script type="text/babel"> function WarningBanner(props) { if (!props.warn) { return null; } return ( <div className="warning"> 警告! </div> ); } class Page extends React.Component { constructor(props) { super(props); this.state = {showWarning: true} this.handleToggleClick = this.handleToggleClick.bind(this); } handleToggleClick() { this.setState(prevState => ({ showWarning: !prevState.showWarning })); } render() { return ( <div> <WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}> {this.state.showWarning ? '隐藏' : '显示'} </button> </div> ); } } ReactDOM.render( <Page />, document.getElementById('example') ); </script> </body> </html>
组件的 render 方法返回 null 并不会影响该组件生命周期方法的回调。例如,componentWillUpdate 和 componentDidUpdate 依然能够被调用。
咱们可使用 JavaScript 的 map() 方法来建立列表
使用 map() 方法遍历数组生成了一个 1 到 5 的数字列表:
const numbers = [1,2,3,4,5]; const listItems = numbers.map((item)=> <li>{item}<li/> ) ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('example') );
咱们能够将以上实例重构成一个组件,组件接收数组参数,每一个列表元素分配一个 key,否则会出现警告 a key should be provided for list items,意思就是须要包含 key:
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
Keys 能够在 DOM 中的某些元素被增长或删除的时候帮助 React 识别哪些元素发生了变化。所以你应当给数组中的每个元素赋予一个肯定的标识。
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> );
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。一般,咱们使用来自数据的 id 做为元素的 key:
const todoItems = todos.map((todo) => <li key={todo.id}> {todo.text} </li> );
当元素没有肯定的 id 时,你可使用他的序列号索引 index 做为 key:
const todoItems = todos.map((todo, index) => // 只有在没有肯定的 id 时使用 <li key={index}> {todo.text} </li> );
若是列表能够从新排序,咱们不建议使用索引来进行排序,由于这会致使渲染变得很慢。
元素的 key 只有在它和它的兄弟节点对比时才有意义。
比方说,若是你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 <ListItem /> 元素上,而不是放在 ListItem 组件中的 <li> 元素上。
错误示范:
function ListItem(props) { const value = props.value; return ( // 错啦!你不须要在这里指定key: <li key={value.toString()}> {value} </li> ); } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => //错啦!元素的key应该在这里指定: <ListItem value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
function ListItem(props) { // 对啦!这里不须要指定key: return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 又对啦!key应该在数组的上下文中被指定 <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不须要是全局惟一的。当咱们生成两个不一样的数组时,咱们可使用相同的键。
function Blog(props) { const sidebar = ( <ul> {props.posts.map((post) => <li key={post.id}> {post.title} </li> )} </ul> ); const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3> <p>{post.content}</p> </div> ); return ( <div> {sidebar} <hr /> {content} </div> ); } const posts = [ {id: 1, title: 'Hello World', content: 'Welcome to learning React!'}, {id: 2, title: 'Installation', content: 'You can install React from npm.'} ]; ReactDOM.render( <Blog posts={posts} />, document.getElementById('example') );
key 会做为给 React 的提示,但不会传递给你的组件。若是您的组件中须要使用和 key 相同的值,请将其做为属性传递:
const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> ); Post 组件能够读出 props.id,可是不能读出 props.key。
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); }
JSX 容许在大括号中嵌入任何表达式,因此咱们能够在 map() 中这样使用:
function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul> ); }
设置状态:setState
替换状态:replaceState
设置属性:setProps
替换属性:replaceProps
强制更新:forceUpdate
获取DOM节点:findDOMNode
判断组件挂载状态:isMounted
setState(object nextState[, function callback])
nextState,将要设置的新状态,该状态会和当前的state合并
callback,可选参数,回调函数。该函数会在setState设置成功,且组件从新渲染后调用。
合并nextState和当前state,并从新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
不能在组件内部经过this.state修改状态,由于该状态会在调用setState()后被替换。
setState()并不会当即改变this.state,而是建立一个即将处理的state。setState()并不必定是同步的,为了提高性能React会批量执行state和DOM渲染。
setState()老是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class Counter extends React.Component{ constructor(props) { super(props); this.state = {clickCount: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(function(state) { return {clickCount: state.clickCount + 1}; }); } render () { return (<h2 onClick={this.handleClick}>点我!点击次数为: {this.state.clickCount}</h2>); } } ReactDOM.render( <Counter />, document.getElementById('example') ); </script> </body> </html>
replaceState(object nextState[, function callback])
nextState,将要设置的新状态,该状态会替换当前的state。
callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件从新渲染后调用。
replaceState()方法与setState()相似,可是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
setProps(object nextProps[, function callback])
nextProps,将要设置的新属性,该状态会和当前的props合并
callback,可选参数,回调函数。该函数会在setProps设置成功,且组件从新渲染后调用。
设置组件属性,并从新渲染组件。
props至关于组件的数据流,它老是会从父组件向下传递至全部的子组件中。当和一个外部的JavaScript应用集成时,咱们可能会须要向组件传递数据或通知React.render()组件须要从新渲染,可使用setProps()。
更新组件,我能够在节点上再次调用React.render(),也能够经过setProps()方法改变组件属性,触发组件从新渲染。
replaceProps(object nextProps[, function callback])
nextProps,将要设置的新属性,该属性会替换当前的props。
callback,可选参数,回调函数。该函数会在replaceProps设置成功,且组件从新渲染后调用。
replaceProps()方法与setProps相似,但它会删除原有 props。
forceUpdate([function callback])
callback,可选参数,回调函数。该函数会在组件render()方法调用后调用。
forceUpdate()方法会使组件调用自身的render()方法从新渲染组件,组件的子组件也会调用本身的render()。可是,组件从新渲染时,依然会读取this.props和this.state,若是状态没有改变,那么React只会更新DOM。
forceUpdate()方法适用于this.props和this.state以外的组件重绘(如:修改了this.state后),经过该方法通知React须要调用render()
通常来讲,应该尽可能避免使用forceUpdate(),而仅从this.props和this.state中读取状态并由React触发render()调用。
DOMElement findDOMNode()
返回值:DOM元素DOMElement
若是组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当render返回null 或 false时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法颇有用,如:获取表单字段的值和作一些 DOM 操做。
bool isMounted()
返回值:true或false,表示组件是否已挂载到DOM中
isMounted()方法用于判断组件是否已挂载到DOM中。可使用该方法保证了setState()和forceUpdate()在异步场景下的调用不会出错。
组件的生命周期可分红三个状态:
Mounting:已插入真实 DOM
Updating:正在被从新渲染
Unmounting:已移出真实 DOM
生命周期的方法有:
componentWillMount 在渲染前调用,在客户端也在服务端。
componentDidMount : 在第一次渲染后调用,只在客户端。以后组件已经生成了对应的DOM结构,能够经过this.getDOMNode()来进行访问。 若是你想和其余JavaScript框架一块儿使用,能够在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操做(防止异步操做阻塞UI)。
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 能够在你确认不须要更新组件时使用。
componentWillUpdate在组件接收到新的props或者state但尚未render时被调用。在初始化时不会被调用。
componentDidUpdate 在组件完成更新后当即调用。在初始化时不会被调用。
componentWillUnmount在组件从 DOM 中移除以前马上被调用。
实例在 Hello 组件加载之后,经过 componentDidMount 方法设置一个定时器,每隔100毫秒从新设置组件的透明度,并从新渲染:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <script type="text/babel"> class Hello extends React.Component { constructor(props) { super(props); this.state = {opacity: 1.0}; } componentDidMount() { this.timer = setInterval(function () { var opacity = this.state.opacity; opacity -= .05; if (opacity < 0.1) { opacity = 1.0; } this.setState({ opacity: opacity }); }.bind(this), 100); } render () { return ( <div style={{opacity: this.state.opacity}}> Hello {this.props.name} </div> ); } } ReactDOM.render( <Hello name="world"/>, document.body ); </script> </body> </html>
React 组件的数据能够经过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时能够将数据存储在 state 中,再用 this.setState 方法从新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。
class UserGist extends React.Component { constructor(props) { super(props); this.state = {username: '', lastGistUrl: ''}; } componentDidMount() { this.serverRequest = $.get(this.props.source, function (result) { var lastGist = result[0]; this.setState({ username: lastGist.owner.login, lastGistUrl: lastGist.html_url }); }.bind(this)); } componentWillUnmount() { this.serverRequest.abort(); } render() { return ( <div> {this.state.username} 用户最新的 Gist 共享地址: <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a> </div> ); } } ReactDOM.render( <UserGist source="https://api.github.com/users/octocat/gists" />, document.getElementById('example') );
以上代码使用 jQuery 完成 Ajax 请求。
TML 表单元素与 React 中的其余 DOM 元素有所不一样,由于表单元素生来就保留一些内部状态。
在 HTML 当中,像 <input>, <textarea>, 和 <select> 这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态一般保存在组件的状态属性中,而且只能用 setState() 方法进行更新。
在实例中咱们设置了输入框 input 值 value = {this.state.data}。在输入框值发生变化时咱们能够更新 state。咱们可使用 onChange 事件来监听 input 的变化,并修改 state。
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { var value = this.state.value; return <div> <input type="text" value={value} onChange={this.handleChange} /> <h4>{value}</h4> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
上面的代码将渲染出一个值为 Hello Runoob! 的 input 元素,并经过 onChange 事件响应更新用户输入的值。
在 React 中,不使用 selected 属性,而在根 select 标签上用 value 属性来表示选中项。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class FlavorForm extends React.Component { constructor(props) { super(props); this.state = {value: 'coconut'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Your favorite flavor is: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> 选择您最喜欢的网站 <select value={this.state.value} onChange={this.handleChange}> <option value="gg">Google</option> <option value="rn">Runoob</option> <option value="tb">Taobao</option> <option value="fb">Facebook</option> </select> </label> <input type="submit" value="提交" /> </form> ); } } ReactDOM.render( <FlavorForm />, document.getElementById('example') ); </script> </body> </html>
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: 'hello world'}) } render() { var value = this.state.value; return <div> <button onClick={this.handleChange}>点我</button> <h4>{value}</h4> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
当你须要从子组件中更新父组件的 state 时,你须要在父组件经过建立事件句柄 (handleChange) ,并做为 prop (updateStateProp) 传递到你的子组件上。实例以下:
class Content extends React.Component { render() { return <div> <button onClick = {this.props.updateStateProp}>点我</button> <h4>{this.props.myDataProp}</h4> </div> } } class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: 'hello world'}) } render() { var value = this.state.value; return <div> <Content myDataProp = {value} updateStateProp = {this.handleChange}></Content> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
React 支持一种很是特殊的属性 Ref ,你能够用来绑定到 render() 输出的任何组件上。
这个特殊的属性容许你引用 render() 返回的相应的支撑实例( backing instance )。这样就能够确保在任什么时候间老是拿到正确的实例。
绑定一个 ref 属性到 render 的返回值上:
<input ref="myInput" />
在其它代码中,经过 this.refs 获取支撑实例:
var input = this.refs.myInput; var inputValue = input.value; var inputRect = input.getBoundingClientRect();
你能够经过使用 this 来获取当前 React 组件,或使用 ref 来获取组件的引用,实例以下:
class MyComponent extends React.Component { handleClick() { // 使用原生的 DOM API 获取焦点 this.refs.myInput.focus(); } render() { // 当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs return ( <div> <input type="text" ref="myInput" /> <input type="button" value="点我输入框获取焦点" onClick={this.handleClick.bind(this)} /> </div> ); } } ReactDOM.render( <MyComponent />, document.getElementById('example') );
咱们获取了输入框的支撑实例的引用,子点击按钮后输入框获取焦点。
咱们也可使用 getDOMNode()方法获取DOM元素