React 构建状态 新版本

React 是一个用于构建用户界面的JavaScript库。

  • 用做UI: 许多人把React当做MVC设计模式中的视图(view),当把React成为你的技术掌握之后, 它可以很轻松应用于一个小功能的项目。
  • 虚拟DOM:React用一个”虚拟DOM”实现了超高的性能,配合nodeJS也可以实现在服务端的渲染,不存在耗时的浏览器dom渲染。
  • 数据流: React是一种减少引用数据流的实现方式,并且比传统的方式更容易实现数据绑定。

NEW! 查看我们最新的项目React Native, 它使用React和JavaScript创建本地应用(比如Android和iOS的APP)。

实例

class HelloMessage extends React.Component{

    render(){

        return <div>你好 {this.props.name}</div>;

    }

}

ReactDOM.render(

    <HelloMessage name="W3Cschool" />,

    document.getElementById('example')

);


尝试一下 »


此示例将“你好 W3Cschool”呈现在页面里(页面中的id为example的元素里)。

你会注意到我们使用类似HTML的语法,我们称之为JSX。 React不一定需要使用JSX,但是它使代码更可读,写它感觉像写HTML。

 React中包含一种简单的变换,它允许将JSX转换为本地JavaScript,供浏览器进行使用。

 没有转换的JSX是不能直接在本地浏览器上运行的。

安装

对于初学者而言,最快的方法是在HTML中引用CDN提供的JavaScript库:

<script src="https://unpkg.com/react@17/umd/react.production.min.js" rel="external nofollow" ></script>

<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" rel="external nofollow" ></script>

<script src="https://unpkg.com/babel-standalone@6/babel.min.js" rel="external nofollow" ></script>



React 是一个用于构建用户界面的JavaScript 库。

React主要用于构建UI,很人多认为 React 是 MVC 中的 V(视图)。

React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。

React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。



React 特点

  • 1.声明式设计 −React采用声明范式,可以轻松描述应用。

  • 2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。

  • 3.灵活 −React可以与已知的库或框架很好地配合。

  • 4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。

  • 5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。

  • 6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。


阅读本教程前,您需要了解的知识:

在开始学习 React 之前,您需要具备以下基础知识:


React 第一个实例

在每个章节中,您可以在线编辑实例,然后点击按钮查看结果。

本教程使用了 React 的版本为 v17.0.2,你可以在官网 http://facebook.github.io/react/ 下载最新版。

React 实例

<div id="example"></div>
<script type="text/babel">
  ReactDOM.render(
    <h1>学编程,就到W3Cschool!</h1>,
    document.getElementById('example')
  );
</script>

尝试一下 »

React 可以直接下载使用,下载包中也提供了很多学习的实例。

本教程使用了 React 的版本为 v17.0.2,你可以在官网 http://facebook.github.io/react/ 下载最新版。

你也可以直接使用 React CDN 库,地址如下:

<script src="https://unpkg.com/react@17/umd/react.production.min.js" rel="external nofollow" rel="external nofollow" ></script>

<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" rel="external nofollow" rel="external nofollow" ></script>

<script src="https://unpkg.com/babel-standalone@6/babel.min.js" rel="external nofollow" rel="external nofollow" ></script>

使用实例

实例

以下实例展示了一个h1标题的输出

<!DOCTYPE html>

<html>

  <head>

    <meta charset="UTF-8" />

    <title>Hello React!</title>

    <script src="https://unpkg.com/react@17/umd/react.production.min.js" rel="external nofollow" rel="external nofollow" ></script>

    <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" rel="external nofollow" rel="external nofollow" ></script>

    <script src="https://unpkg.com/babel-standalone@6/babel.min.js" rel="external nofollow" rel="external nofollow" ></script>

  </head>

  <body>

    <div id="example"></div>

    <script type="text/babel">

      ReactDOM.render(

        <h1>学编程,就到W3Cschool</h1>,

        document.getElementById('example')

      );

    </script>

  </body>

</html>


尝试一下 »

实例解析:

实例中我们引入了三个库:​ react.production.min.js​ 、​react-dom.production.min.js​ 和 ​babel.min.js​:

  • react.production.min.js - React 的核心库
  • react-dom.production.min.js - 提供与 DOM 相关的功能
  • babel.min.js - Babel 可以将 ES6 代码转为 ES5 代码,这样我们就能在目前不支持 ES6 的浏览器上执行 React 代码。
  • Babel 内嵌了对 JSX 的支持
  • 通过将 Babel 和 babel-sublime 包(package)一同使用可以让源码的语法渲染上升到一个全新的水平

 注意:在浏览器中使用Babel来编译JSX效率是非常低的,一般来说前端开发工作者在页面部署到网站前先使用babel进行编译。

ReactDOM.render(	<h1>学编程,就到W3Cschool</h1>,	document.getElementById('example'));

以上代码将一个 h1 标题,插入 id="example" 节点中。

注意:

如果我们需要使用 JSX,则 <script> 标签的 type 属性需要设置为 text/babel


通过 npm 使用 React

如果你的系统还不支持 Node.js 及 NPM 可以参考我们的 Node.js 教程

我们建议在 React 中使用 CommonJS 模块系统,比如 browserify 或 webpack,本教程使用 webpack。

国内使用 npm 速度很慢,你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:

$ npm install -g cnpm --registry=https://registry.npmmirror.com$ npm config set registry https://registry.npmmirror.com

这样就可以使用 cnpm 命令来安装模块了:

$ cnpm install [name]

更多信息可以查阅:http://npm.taobao.org/

 还有一款新的构建工具非常值得一试——vite,给你带来更快的构建体验,相关教程可以前往vite教程进行了解!

使用webpack搭建React

第一步、安装全局包

$ npm install babel -g$ npm install webpack -g$ npm install webpack-dev-server -g

第二步、创建根目录

创建一个根目录,目录名为:reactApp,再使用 npm init 初始化,生成 package.json 文件:

$ mkdir reactApp$ cd reactApp/$ npm initname: (reactApp) youj-react-testversion: (1.0.0) description: W3Cschool教程 react 测试entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /Users/laolan/www/reactApp/package.json:{  "name": "youj-react-test",  "version": "1.0.0",  "description": "W3Cschool教程 react 测试",  "main": "index.js",  "scripts": {    "test": "echo "Error: no test specified" && exit 1"  },  "author": "",  "license": "ISC"}Is this ok? (yes)

第三步、添加依赖包及插件

因为我们要使用 React, 所以我们需要先安装它,--save 命令用于将包添加至 package.json 文件。

$ npm install react --save$ npm install react-dom --save

同时我们也要安装一些 babel 插件

$ npm install babel-core$ npm install babel-loader$ npm install babel-preset-react$ npm install babel-preset-es2015

第四步、创建文件

接下来我们创建一些必要文件:

$ touch index.html$ touch App.jsx$ touch main.js$ touch webpack.config.js

 注:touch是linux下创建新文件的命令,在Windows中可以使用ni命令替换touch命令。即

ni index.htmlni App.jsxni main.jsni webpack.config.js

第五步、设置编译器,服务器,载入器

打开 webpack.config.js 文件添加以下代码:

 var config = {   entry: './main.js',	   output: {      path:'./',      filename: 'index.js',   },	   devServer: {      inline: true,      port: 7777   },	   module: {      loaders: [ {         test: /.jsx?$/,         exclude: /node_modules/,         loader: 'babel',			         query: {            presets: ['es2015', 'react']         }      }]   }	}module.exports = config;
  • entry: 指定打包的入口文件 main.js
  • output:配置打包结果,path定义了输出的文件夹,filename则定义了打包结果文件的名称。
  • devServer:设置服务器端口号为 7777,端口后你可以自己设定 。
  • module:定义了对模块的处理逻辑,这里可以用loaders定义了一系列的加载器,以及一些正则。当需要加载的文件匹配test的正则时,就会调用后面的loader对文件进行处理,这正是webpack强大的原因。

现在打开 package.json 文件,找到 ​"scripts" ​中的​ "test" "echo "Error: no test specified" && exit 1"​ 使用以下代码替换:

"start": "webpack-dev-server --hot"

替换后的 package.json 文件 内容如下:

{  "name": "youj-react-test",  "version": "1.0.0",  "description": "W3Cschool教程 react 测试",  "main": "index.js",  "scripts": {	"start": "webpack-dev-server --hot"  },  "author": "",  "license": "ISC",  "dependencies": {    "react": "^17.0.2",    "react-dom": "^17.0.2"
}}

现在我们可以使用​ npm start ​命令来启动服务。​--hot ​命令会在文件变化后重新载入,这样我们就不需要在代码修改后重新刷新浏览器就能看到变化。

第六步、index.html

设置​<div id = "app">​ 为我们应用的根元素,并引入 index.js 脚本文件。

<!DOCTYPE html><html>   <head>      <meta charset = "UTF-8">      <title>React App - W3Cschool教程(51coolma.cn)</title>   </head>   <body>      <div id = "app"></div>      <script src = "index.js"></script>   </body></html>

第七步、App.jsx 和 main.js

这是第一个 react 组件。后面的章节我们会详细介绍 React 组件。这个组件将输出 Hello World!!!

App.jsx 文件代码

import React from 'react';class App extends React.Component {   render() {      return (         <div>            Hello World!!!<br />            欢迎来到W3Cschool教程学习!!!         </div>      );   }}export default App;

我们需要引入组件并将其渲染到根元素 App 上,这样我们才可以在浏览器上看到它。

main.js 文件代码

import React from 'react';import ReactDOM from 'react-dom';import App from './App.jsx';ReactDOM.render(<App />, document.getElementById('app'))

注意:

如果想要组件可以在任何的应用中使用,需要在创建后使用 export 将其导出,在使用组件的文件使用 import 将其导入。

第八步、运行服务

完成以上配置后,我们即可运行该服务:

$ npm start

通过浏览器访问 http://localhost:7777/,输出结果如下:


完整实例下载

以上测试实例各文件代码下载地址:reactApp.zip


JSX 是 React 的核心组成部分,它使用 XML 标记的方式去直接声明界面,界面组件之间可以互相嵌套。

React 使用 JSX 来替代常规的 JavaScript。

JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。

我们不需要一定使用 JSX,但它有以下优点:

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
  • 使用 JSX 编写模板更加简单快速。

使用 JSX

JSX 看起来类似 HTML ,我们可以看下实例:

ReactDOM.render(    <h1>Hello, world!</h1>,    document.getElementById('example'));

我们可以在以上代码中嵌套多个 HTML 标签,需要使用一个 div 元素包裹它,实例中的 p 元素添加了自定义属性 data-myattribute,添加自定义属性需要使用 data- 前缀。

ReactDOM.render(    <div>	<h1>W3Cschool教程</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 文件:

<body>    <div id="example"></div>    <script type="text/babel" src="helloworld_react.js"></script></body>

尝试一下 »


JavaScript 表达式

我们可以在 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 : 80,    color : "#FF0000"};ReactDOM.render(    <h1 style = {myStyle}>W3Cschool教程</h1>,    document.getElementById('example'));

尝试一下 »


注释

注释需要写在花括号中,实例如下:

ReactDOM.render(    <div>        <h1>W3Cschool教程</h1>        {/*注释...*/}    </div>,    document.getElementById('example'));

尝试一下 »


数组

JSX 允许在模板中插入数组,数组会自动展开所有成员:

var arr = [    <h1>W3Cschool教程</h1>,    <h2>从W3Cschool开始!</h2>,];ReactDOM.render(    <div>{arr}</div>,    document.getElementById('example'));

尝试一下 »


HTML 标签 vs. React 组件

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,一些标识符像 classfor 不建议作为 XML 属性名。作为替代,React DOM 使用 classNamehtmlFor 来做对应的属性。


组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思。

组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。

函数组件与 class 组件

定义组件最简单的方式就是编写 JavaScript 函数:

function Welcome(props) {  return <h1>Hello, {props.name}</h1>;}

该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “​props​”(代表属性)对象与并返回一个 React 元素。

这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。


你同时还可以使用 ES6 的 class 来定义组件:

class Welcome extends React.Component {  render() {    return <h1>Hello, {this.props.name}</h1>;  }}

上述两个组件在 React 里是等效的。


渲染组件

之前,我们遇到的 React 元素都只是 DOM 标签:

const element = <div />;

不过,React 元素也可以是用户自定义的组件:

const element = <Welcome name="Sara" />;

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。

例如,这段代码会在页面上渲染 “Hello, Sara”:

function Welcome(props) {      return <h1>Hello, {props.name}</h1>;}const element = <Welcome name="Sara" />;ReactDOM.render(  element,  document.getElementById('root'));

在 CodePen 上尝试

让我们来回顾一下这个例子中发生了什么:

  1. 我们调用 ReactDOM.render() 函数,并传入 <Welcome name="Sara" /> 作为参数。
  2. React 调用 Welcome 组件,并将 {name: 'Sara'} 作为 props 传入。
  3. Welcome 组件将 <h1>Hello, Sara</h1> 元素作为返回值。
  4. React DOM 将 DOM 高效地更新为 <h1>Hello, Sara</h1>。
注意: 组件名称必须以大写字母开头。
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,
 代表 HTML 的 div 标签,而   则代表一个组件,并且需在作用域内使用 Welcome。

组合组件

组件可以在其输出中引用其他组件。这就可以让我们用同一组件来抽象出任意层次的细节。

按钮,表单,对话框,甚至整个屏幕的内容:在 React 应用程序中,这些通常都会以组件的形式表示。

例如,我们可以创建一个可以多次渲染 Welcome 组件的 App 组件:

function Welcome(props) {  return <h1>Hello, {props.name}</h1>;}function App() {  return (    <div>        <Welcome name="Sara" />              <Welcome name="Cahal" />              <Welcome name="Edite" />        </div>  );}ReactDOM.render(  <App />,  document.getElementById('root'));

在 CodePen 上尝试

通常来说,每个新的 React 应用程序的顶层组件都是 App 组件。

但是,如果你将 React 集成到现有的应用程序中,你可能需要使用像 Button 这样的小组件,并自下而上地将这类组件逐步应用到视图层的每一处。

提取组件

将组件拆分为更小的组件。

例如,参考如下 Comment 组件:

function Comment(props) {  return (    <div className="Comment">      <div className="UserInfo">        <img className="Avatar"          src={props.author.avatarUrl}          alt={props.author.name}        />        <div className="UserInfo-name">          {props.author.name}        </div>      </div>      <div className="Comment-text">        {props.text}      </div>      <div className="Comment-date">        {formatDate(props.date)}      </div>    </div>  );}

在 CodePen 上尝试

该组件用于描述一个社交媒体网站上的评论功能,它接收 author(对象),text (字符串)以及 date(日期)作为 props。

该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中提取一些组件出来。

首先,我们将提取 Avatar 组件:

function Avatar(props) {  return (    <img className="Avatar"      src={props.user.avatarUrl}      alt={props.user.name}    />  );}

Avatar 不需知道它在 Comment 组件内部是如何渲染的。因此,我们给它的 props 起了一个更通用的名字:user,而不是 author。

我们建议从组件自身的角度命名 props,而不是依赖于调用组件的上下文命名。

我们现在针对 Comment 做些微小调整:

function Comment(props) {  return (    <div className="Comment">      <div className="UserInfo">        <Avatar user={props.author} />                <div className="UserInfo-name">          {props.author.name}        </div>      </div>      <div className="Comment-text">        {props.text}      </div>      <div className="Comment-date">        {formatDate(props.date)}      </div>    </div>  );}

接下来,我们将提取 UserInfo 组件,该组件在用户名旁渲染 Avatar 组件:

function UserInfo(props) {  return (    <div className="UserInfo">          <Avatar user={props.user} />          <div className="UserInfo-name">        {props.user.name}      </div>        </div>      );}

进一步简化 Comment 组件:

function Comment(props) {  return (    <div className="Comment">      <UserInfo user={props.author} />            <div className="Comment-text">        {props.text}      </div>      <div className="Comment-date">        {formatDate(props.date)}      </div>    </div>  );}

在 CodePen 上尝试

最初看上去,提取组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。

根据经验来看,如果 UI 中有一部分被多次使用(Button,Panel,Avatar),或者组件本身就足够复杂(App,FeedStory,Comment),那么它就是一个可复用组件的候选项。

Props 的只读性

组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。来看下这个 sum 函数:

function sum(a, b) {  return a + b;}

这样的函数被称为“纯函数”,因为该函数不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。

相反,下面这个函数则不是纯函数,因为它更改了自己的入参:

function withdraw(account, amount) {  account.total -= amount;}

React 非常灵活,但它也有一个严格的规则:

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。



通过调用 ReactDOM.render() 来修改我们想要渲染的元素:

function tick() {  const element = (    <div>      <h1>Hello, world!</h1>      <h2>It is {new Date().toLocaleTimeString()}.</h2>    </div>  );  ReactDOM.render(element,document.getElementById('root'));}setInterval(tick, 1000);

在 CodePen 上尝试

如何封装真正可复用的 Clock 组件。将设置自己的计时器并每秒更新一次。

我们可以从封装时钟的外观开始:

function Clock(props) {  return (    <div>              <h1>Hello, world!</h1>              <h2>It is {props.date.toLocaleTimeString()}.</h2>        </div>      );}function tick() {  ReactDOM.render(    <Clock date={new Date()} />,        document.getElementById('root')  );}setInterval(tick, 1000);

在 CodePen 上尝试

然而,它忽略了一个关键的技术细节:Clock 组件需要设置一个计时器,并且需要每秒更新 UI。

理想情况下,我们希望只编写一次代码,便可以让 Clock 组件自我更新:

ReactDOM.render(    <Clock />,      document.getElementById('root'));

我们需要在 Clock 组件中添加 “state” 来实现这个功能。

State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

将函数组件转换成 class 组件

通过以下五步将 Clock 的函数组件转成 class 组件:

  1. 创建一个同名的 ES6 class,并且继承于 React.Component。
  2. 添加一个空的 render() 方法。
  3. 将函数体移动到 render() 方法之中。
  4. 在 render() 方法中使用 this.props 替换 props。
  5. 删除剩余的空函数声明。
class Clock extends React.Component {  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>      </div>    );  }}

在 CodePen 上尝试

现在 Clock 组件被定义为 class,而不是函数。

每次组件更新时 render 方法都会被调用,但只要在相同的 DOM 节点中渲染 <Clock /> ,就仅有一个 Clock 组件的 class 实例被创建使用。

这就使得我们可以使用如 state 或生命周期方法等很多其他特性。

向 class 组件中添加局部的 state

我们通过以下三步将 date 从 props 移动到 state 中:

  1. 把 render() 方法中的 this.props.date 替换成 this.state.date :
class Clock extends React.Component {  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>              </div>    );  }}
  1. 添加一个 class 构造函数,然后在该函数中为 this.state 赋初值:
class Clock extends React.Component {    constructor(props) {        super(props);        this.state = {date: new Date()};      }  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}

通过以下方式将 props 传递到父类的构造函数中:

  constructor(props) {    super(props);        this.state = {date: new Date()};  }

Class 组件应该始终使用 props 参数来调用父类的构造函数。

  1. 移除 <Clock /> 元素中的 date 属性:
ReactDOM.render(    <Clock />,      document.getElementById('root'));

我们之后会将计时器相关的代码添加到组件中。

代码如下:

class Clock extends React.Component {    constructor(props) {            super(props);            this.state = {date: new Date()};      }    render() {        return (            <div>            <h1>Hello, world!</h1>            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>                  </div>        );    }}ReactDOM.render(  <Clock />,  document.getElementById('root'));

在 CodePen 上尝试

接下来,我们会设置 Clock 的计时器并每秒更新它。

将生命周期方法添加到 Class 中

在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。

当 Clock 组件第一次被渲染到 DOM 中的时候,就为其设置一个计时器。

这在 React 中被称为“挂载(mount)”。

同时,当 DOM 中 Clock 组件被删除的时候,应该清除计时器。

这在 React 中被称为“卸载(unmount)”。

我们可以为 class 组件声明一些特殊的方法,当组件挂载或卸载时就会去执行这些方法:

class Clock extends React.Component {  constructor(props) {    super(props);    this.state = {date: new Date()};  }  componentDidMount() {  }  componentWillUnmount() {  }  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}

这些方法叫做“生命周期方法”。

componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器:

componentDidMount() {    this.timerID = setInterval(() => this.tick(),1000);  }

接下来把计时器的 ID 保存在 this 之中(this.timerID)。

尽管 this.props 和 this.state 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。

我们会在 componentWillUnmount() 生命周期方法中清除计时器:

componentWillUnmount() {    clearInterval(this.timerID);  }

最后,我们会实现一个叫 tick() 的方法,Clock 组件每秒都会调用它。

使用 this.setState() 来时刻更新组件 state:

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>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}ReactDOM.render(  <Clock />,  document.getElementById('root'));

在 CodePen 上尝试

现在时钟每秒都会刷新。

让我们来快速概括一下发生了什么和这些方法的调用顺序:

  1. 当 <Clock /> 被传给 ReactDOM.render()的时候,React 会调用 Clock 组件的构造函数。因为 Clock 需要显示当前的时间,所以它会用一个包含当前时间的对象来初始化 this.state。我们会在之后更新 state。
  2. 之后 React 会调用组件的 render() 方法。这就是 React 确定该在页面上展示什么的方式。然后 React 更新 DOM 来匹配 Clock 渲染的输出。
  3. 当 Clock 的输出被插入到 DOM 中后,React 就会调用 ComponentDidMount() 生命周期方法。在这个方法中,Clock 组件向浏览器请求设置一个计时器来每秒调用一次组件的 tick() 方法。
  4. 浏览器每秒都会调用一次 tick() 方法。 在这方法之中,Clock 组件会通过调用 setState() 来计划进行一次 UI 更新。得益于 setState() 的调用,React 能够知道 state 已经改变了,然后会重新调用 render() 方法来确定页面上该显示什么。这一次,render() 方法中的 this.state.date 就不一样了,如此以来就会渲染输出更新过的时间。React 也会相应的更新 DOM。
  5. 一旦 Clock 组件从 DOM 中被移除,React 就会调用 componentWillUnmount() 生命周期方法,这样计时器就停止了。

正确地使用 State

关于 setState() 你应该了解三件事:

不要直接修改 State

例如,此代码不会重新渲染组件:

// Wrongthis.state.comment = 'Hello';

而是应该使用 setState():

// Correctthis.setState({comment: 'Hello'});

构造函数是唯一可以给 this.state 赋值的地方:

State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。

因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。

例如,此代码可能会无法更新计数器:

// Wrongthis.setState({  counter: this.state.counter + this.props.increment,});

要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:

// Correctthis.setState((state, props) => ({  counter: state.counter + props.increment}));

上面使用了箭头函数,不过使用普通的函数也同样可以:

// Correctthis.setState(function(state, props) {  return {    counter: state.counter + props.increment  };});

State 的更新会被合并

当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。

例如,你的 state 包含几个独立的变量:

constructor(props) {    super(props);    this.state = {        posts: [],              comments: []        };}

然后你可以分别调用 setState() 来单独地更新它们:

  componentDidMount() {    fetchPosts().then(response => {        this.setState({            posts: response.posts              });    });    fetchComments().then(response => {      this.setState({        comments: response.comments      });    });  }

这里的合并是浅合并,所以 this.setState({comments}) 完整保留了 this.state.posts, 但是完全替换了 this.state.comments。

数据是向下流动的

不管是父组件或是子组件都无法知道某个组件是有状态的还是无状态的,并且它们也并不关心它是函数组件还是 class 组件。

这就是为什么称 state 为局部的或是封装的的原因。除了拥有并设置了它的组件,其他组件都无法访问。

组件可以选择把它的 state 作为 props 向下传递到它的子组件中:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

这对于自定义组件同样适用:

<FormattedDate date={this.state.date} />

FormattedDate 组件会在其 props 中接收参数 date,但是组件本身无法知道它是来自于 Clock 的 state,或是 Clock 的 props,还是手动输入的:

function FormattedDate(props) {  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;}

在 CodePen 上尝试

这通常会被叫做“自上而下”或是“单向”的数据流。任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。

如果你把一个以组件构成的树想象成一个 props 的数据瀑布的话,那么每一个组件的 state 就像是在任意一点上给瀑布增加额外的水源,但是它只能向下流动。

为了证明每个组件都是真正独立的,我们可以创建一个渲染三个 Clock 的 App 组件:

function App() {  return (    <div>        <Clock />              <Clock />              <Clock />        </div>  );}ReactDOM.render(  <App />,  document.getElementById('root'));

在 CodePen 上尝试

每个 Clock 组件都会单独设置它自己的计时器并且更新它。

在 React 应用中,组件是有状态组件还是无状态组件属于组件实现的细节,它可能会随着时间的推移而改变。你可以在有状态的组件中使用无状态的组件,反之亦然。


本节介绍了 React Props。

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。

这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 state 来传递数据。


使用 Props

以下实例演示了如何在组件中使用 props:

function HelloMessage(props) {    return <h1>Hello {props.name}!</h1>;} const element = <HelloMessage name="W3Cschool"/>; ReactDOM.render(    element,    document.getElementById('example'));

尝试一下 »

实例中 name 属性通过 this.props.name 来获取。


默认 Props

你可以通过 getDefaultProps() 方法为 props 设置默认值,实例如下:

class HelloMessage extends React.Component {  render() {    return (      <h1>Hello, {this.props.name}</h1>    );  }} HelloMessage.defaultProps = {  name: 'W3Cschool'}; const element = <HelloMessage/>; ReactDOM.render(  element,  document.getElementById('example'));

尝试一下 »


State 和 Props

以下实例演示了如何在应用中组合使用 state 和 props 。

我们可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。

在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据。

class WebSite extends React.Component {

constructor() {

    super();

    this.state = {

        name: "编程狮",

        site: "https://www.51coolma.cn"

    }

}

render() { return ( <div> <Name name={this.state.name} /> <Link site={this.state.site} /> </div> ); }}class Name extends React.Component { render() { return ( <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'));

尝试一下 »


Props 验证

React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库。

<script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js" rel="external nofollow" ></script>

Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。

当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

以下实例创建一个 Mytitle 组件,属性 title 是必须的且是字符串,非字符串类型会自动转换为字符串:

var title = "W3Cschool教程";class MyTitle extends React.Component {  render() {    return (      <h1>Hello, {this.props.title}</h1>    );  }} MyTitle.propTypes = {  title: PropTypes.string};ReactDOM.render(    <MyTitle title={title} />,    document.getElementById('example'));

尝试一下 »


更多验证器说明如下:

MyComponent.propTypes = {    // 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的   optionalArray: React.PropTypes.array,    optionalBool: React.PropTypes.bool,    optionalFunc: React.PropTypes.func,    optionalNumber: React.PropTypes.number,    optionalObject: React.PropTypes.object,    optionalString: React.PropTypes.string,     // 可以被渲染的对象 numbers, strings, elements 或 array    optionalNode: React.PropTypes.node,     //  React 元素    optionalElement: React.PropTypes.element,     // 用 JS 的 instanceof 操作符声明 prop 为类的实例。    optionalMessage: React.PropTypes.instanceOf(Message),     // 用 enum 来限制 prop 只接受指定的值。    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),     // 可以是多个对象类型中的一个    optionalUnion: React.PropTypes.oneOfType([      React.PropTypes.string,      React.PropTypes.number,      React.PropTypes.instanceOf(Message)    ]),     // 指定类型组成的数组    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),     // 指定类型的属性构成的对象    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),     // 特定 shape 参数的对象    optionalObjectWithShape: React.PropTypes.shape({      color: React.PropTypes.string,      fontSize: React.PropTypes.number    }),     // 任意类型加上 `isRequired` 来使 prop 不可空。    requiredFunc: React.PropTypes.func.isRequired,     // 不可空的任意类型    requiredAny: React.PropTypes.any.isRequired,     // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。    customProp: function(props, propName, componentName) {      if (!/matchme/.test(props[propName])) {        return new Error('Validation failed!');      }    }  }}


React 组件 API

在本章节中我们将讨论 React 组件 API。

我们将讲解以下7个方法:

  • 设置状态:​setState
  • 替换状态:​replaceState
  • 设置属性:​setProps
  • 替换属性:​replaceProps
  • 强制更新:​forceUpdate
  • 获取DOM节点:​findDOMNode
  • 判断组件挂载状态:​isMounted

设置状态:setState

setState(object nextState[, function callback])

参数说明

  • nextState,将要设置的新状态,该状态会和当前的state合并
  • callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。

合并nextState和当前state,并重新渲染组件。

setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。

关于setState

注意: 不能在组件内部通过​this.state​修改状态,因为该状态会在调用​setState()​后被替换。

setState() 并不会立即改变 this.state,而是创建一个即将处理的state。

setState() 并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。

setState() 总是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。

实例

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'));

尝试一下 »

实例中通过点击 h2 标签来使得点击计数器加 1。

替换状态:replaceState

replaceState(object nextState[, function callback])
  • nextState,将要设置的新状态,该状态会替换当前的state。
  • callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。

replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。

设置属性:setProps

setProps(object nextProps[, function callback])
  • nextProps,将要设置的新属性,该状态会和当前的props合并
  • callback,可选参数,回调函数。该函数会在setProps设置成功,且组件重新渲染后调用。

设置组件属性,并重新渲染组件。

props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。当和一个外部的JavaScript应用集成时,我们可能会需要向组件传递数据或通知React.render()组件需要重新渲染,可以使用setProps()。

更新组件,我可以在节点上再次调用React.render(),也可以通过setProps()方法改变组件属性,触发组件重新渲染。

替换属性:replaceProps

replaceProps(object nextProps[, function callback])
  • nextProps,将要设置的新属性,该属性会替换当前的props。
  • callback,可选参数,回调函数。该函数会在replaceProps设置成功,且组件重新渲染后调用。

replaceProps()方法与setProps类似,但它会删除原有

props

强制更新:forceUpdate

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()调用。

获取DOM节点:findDOMNode

DOMElement findDOMNode()
  • 返回值:DOM元素DOMElement

如果组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当render返回null 或 false时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。

判断组件挂载状态:isMounted

bool isMounted()
  • 返回值:true或false,表示组件是否已挂载到DOM中

isMounted()方法用于判断组件是否已挂载到DOM中。可以使用该方法保证了setState()和forceUpdate()在异步场景下的调用不会出错。

本文参考:http://itbilu.com/javascript/react/EkACBdqKe.html

相关阅读

HTML DOM 节点


React 组件的生命周期函数,又叫钩子函数,它能响应不同的状态。

在本章节中我们将讨论 React 组件的生命周期。

组件的生命周期可分成三个状态:

  • 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毫秒重新设置组件的透明度,并重新渲染:

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);

尝试一下 »

以下实例初始化 statesetNewnumber 用于更新 state。所有生命周期在 Content 组件中。

class Button extends React.Component {  constructor(props) {      super(props);      this.state = {data: 0};      this.setNewNumber = this.setNewNumber.bind(this);  }    setNewNumber() {    this.setState({data: this.state.data + 1})  }  render() {      return (         <div>            <button onClick = {this.setNewNumber}>INCREMENT</button>            <Content myNumber = {this.state.data}></Content>         </div>      );    }}  class Content extends React.Component {  componentWillMount() {      console.log('Component WILL MOUNT!')  }  componentDidMount() {       console.log('Component DID MOUNT!')  }  componentWillReceiveProps(newProps) {        console.log('Component WILL RECEIVE PROPS!')  }  shouldComponentUpdate(newProps, newState) {        return true;  }  componentWillUpdate(nextProps, nextState) {        console.log('Component WILL UPDATE!');  }  componentDidUpdate(prevProps, prevState) {        console.log('Component DID UPDATE!')  }  componentWillUnmount() {         console.log('Component WILL UNMOUNT!')  }     render() {      return (        <div>          <h3>{this.props.myNumber}</h3>        </div>      );    }}ReactDOM.render(   <div>      <Button />   </div>,  document.getElementById('example'));

尝试一下 »


React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据库可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。

当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

以下实例演示了获取 Github 用户最新 gist 共享描述:

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 请求。

相关教程

AJAX教程


本章节我们将讨论如何在 React 中使用表单。

一个简单是实例

在实例中我们设置了输入框 input 值value = {this.state.data}。在输入框值发生变化时我们可以更新 state。我们可以使用 onChange 事件来监听 input 的变化,并修改 state。

class HelloMessage extends React.Component {  constructor(props) {      super(props);      this.state = {value: 'Hello W3CSchool!'};      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 W3CSchool! 的 input 元素,并通过 onChange 事件响应更新用户输入的值。

实例 2

在以下实例中我么将为大家演示如何在子组件上使用表单。onChange 方法将触发 state 的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面。

你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上。

class Content extends React.Component {  render() {    return  <div>            <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} />             <h4>{this.props.myDataProp}</h4>            </div>;  }}class HelloMessage extends React.Component {  constructor(props) {      super(props);      this.state = {value: 'Hello W3CSchool!'};      this.handleChange = this.handleChange.bind(this);  }   handleChange(event) {    this.setState({value: event.target.value});  }  render() {    var value = this.state.value;    return <div>            <Content myDataProp = {value}               updateStateProp = {this.handleChange}></Content>           </div>;  }}ReactDOM.render(  <HelloMessage />,  document.getElementById('example'));

尝试一下 »


Select 下拉菜单

在 React 中,不使用 selected 属性,而在根 select 标签上用 value 属性来表示选中项。

class Content extends React.Component {  render() {    return  <div>            <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} />             <h4>{this.props.myDataProp}</h4>            </div>;  }}class HelloMessage extends React.Component {  constructor(props) {      super(props);      this.state = {value: 'Hello W3CSchool!'};
this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { var value = this.state.value; return <div> <Content myDataProp = {value} updateStateProp = {this.handleChange}></Content> </div>; }}ReactDOM.render( <HelloMessage />, document.getElementById('example'));

多个表单

当你有处理多个 input 元素时,你可以通过给每个元素添加一个 name 属性,来让处理函数根据 event.target.name 的值来选择做什么。

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="w3">W3CSchool</option>
<option value="tb">Taobao</option> <option value="fb">Facebook</option> </select> </label> <input type="submit" value="提交" /> </form> ); }} ReactDOM.render( <FlavorForm />, document.getElementById('example'));

React 事件

以下实例演示通过 onClick 事件来修改数据:

class HelloMessage extends React.Component {  constructor(props) {      super(props);      this.state = {value: 'Hello W3Cschool!'};      this.handleChange = this.handleChange.bind(this);  }    handleChange(event) {    this.setState({value: '编程狮'})  }  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 W3Cschool!'};      this.handleChange = this.handleChange.bind(this);  }  handleChange(event) {    this.setState({value: '编程狮'})  }  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 属性的值可以是一个字符串也可以是一个函数。

使用方法

绑定一个 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元素