https://www.runoob/react/react-tutorial.html

菜鸟教程的react看起来比较浅,一天就看完了。 感觉赶紧还是看看阮一峰老师的吧

文章目录

  • 一.React 安装
    • 使用官方提供的 CDN 地址:
    • 使用 create-react-app 脚手架快速构建 React 开发环境
  • 二.React 元素渲染
    • 更新元素渲染
  • 三.React JSX
    • 使用 JSX自定义属性
    • 独立文件
    • jsx 条件表达式
    • 样式
    • 注释
    • 数组
  • 四.React 组件
    • 组件实例
    • 实例解析
    • 复合组件实例
  • 五.React State(状态)
    • 将生命周期方法添加到类中
    • 数据自顶向下流动
  • 六.React Props
    • 默认 Props
    • State 和 Props
    • Props 验证
  • 七.React 事件处理
    • React初始渲染监听器
    • 关于jsx的this
    • 向事件处理程序传递参数
  • 八.React 条件渲染
    • 元素变量
    • 与运算符 &&
    • 三目运算符
    • 阻止组件渲染
  • 九.React 列表 & Keys
    • Keys
    • 用keys提取组件
    • key的正确使用方式
    • 元素的 key 在他的兄弟元素之间应该唯一
    • 在 jsx 中嵌入 map()
  • 十.React 组件 API
    • 设置状态:setState
      • 参数说明
      • 关于setState
    • 替换状态:replaceState(废弃)
    • 设置属性:setProps(废弃)
    • 强制更新:forceUpdate
      • 参数说明
    • 获取DOM节点:findDOMNode(废除)
    • 判断组件挂载状态:isMounted(废除)
  • 十一.React 组件生命周期
  • 十二.React AJAX
  • 十三.React 表单与事件
    • 一个简单的实例
      • Select 下拉菜单
      • 多个表单
  • 十四.React Refs
    • 使用方法

一.React 安装

使用官方提供的 CDN 地址:

注意: 在浏览器中使用 Babel 来编译 JSX 效率是非常低的。

使用 create-react-app 脚手架快速构建 React 开发环境

create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境。

create-react-app 自动创建的项目是基于 Webpack + ES6 。

执行以下命令创建项目:

$ cnpm install -g create-react-app //全局安装
$ create-react-app my-app //构建my-app项目
$ cd my-app //切换路径
$ npm start //启动项目(可以直接使用并且打开localhost:3000)

项目的目录结构如下:

my-app/
  README.md
  node_modules/
  package.json
  .gitignore
  public/            # 这个是webpack的配置的静态目录
    favicon.ico
    index.html       # 默认是单页面应用,这个是最终的html的基础模板
    manifest.json
  src/
    App.css          # App根组件的css
    App.js           # App组件代码
    App.test.js
    index.css        # 启动文件样式
    index.js         # 启动的文件(开始执行的入口)!!!!
    logo.svg

启动后(我对app.js做了修改加了,并且vscode的自动排版虽然对reactjs的执行没有影响但是会很难看,需要ctrl+shift+p-修改语言模式-JavaScript React)

二.React 元素渲染

前提:加入react的cdn,并且 type=“text/babel”

<script type="text/babel">...</script>

要将React元素渲染到根DOM节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:

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

更新元素渲染

React 元素都是不可变的。当元素被创建之后,你是无法改变其内容或属性的。

目前更新界面的唯一办法是创建一个新的元素,然后将它传入 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);

以上实例通过 setInterval() 方法,每秒钟调用一次 ReactDOM.render()。

并且将要展示的部分封装起来

除了函数外我们还可以创建一个 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

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

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

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

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

元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。

与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。

要将 React 元素渲染到根 DOM 节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:

var myDivElement = <div className="foo" />; 
ReactDOM.render(myDivElement, document.getElementById('example'));

注意:

由于 JSX 就是 JavaScript,一些标识符像 classfor 不建议作为 XML 属性名。作为替代,React DOM 使用 classNamehtmlFor 来做对应的属性。

使用 JSX自定义属性

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

独立文件

你的 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>

jsx 条件表达式

在 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}>菜鸟教程</h1>,
      	document.getElementById('example')
      );

注释

注释需要写在花括号中

{/*注释...*/}

数组

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

var arr = [
  <h1>菜鸟教程</h1>,
  <h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

四.React 组件

组件实例

将讨论如何使用组件使得我们的应用更容易来管理

接下来我们封装一个输出 “Hello World!” 的组件,组件名为 HelloMessage

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

实例解析

1、我们可以使用函数定义了一个组件

function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}

你也可以使用 ES6 class 来定义一个组件,把return语句封在render(){}里面

class Welcome extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}

2、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 的保留字。

复合组件实例

把不同的React.Component封装在App里面

多个属性的传入注意不用逗号或分号隔开而是空格符隔开:

var myStyle = {color:'red',textAlign:'center'}

class Name extends React.Component {
  render() {
    return <h1 style={myStyle}>网站名称:{this.props.name}</h1>;
  }
}
class Url extends React.Component {
  render() {
    return <h2>网站地址:{this.props.url}</h2>;
  }
}
class Nickname extends React.Component {
  render() {
    return <h2>网站地址:{this.props.nickname}</h2>;
  }
}
class App extends React.Component {
render(){
    return (
        <div>
            <Name name={this.props.name}/> {/*传入"菜鸟教程"*/}
            <Url  url={this.props.url}/>
            <Nickname  nickname={this.props.nickname}/>
        </div>
    );
	}
}
/*function App(props) {
*    return (
*        <div>
*            <Name name={props.name}/>
*            <Url  url={props.url}/>
*            <Nickname  nickname={props.nickname}/>
*       </div>
*    );
}*/
ReactDOM.render(
     <App name={"菜鸟教程"} url={"http://www.runoob"} nickname={"Runoob"}/>,
    document.getElementById('example')
);

五.React State(状态)

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。

添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。

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

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

每当 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()
    },
    ()=>{console.log(this.state)}// this.setState的执行回调
    );
  }
 
  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() 钩子中卸载定时器。
  • 如果需要修改this.state中的数据 必须调用this.setstate这个方法.
  • 使用对this.state赋值并没有什么作用,官方提醒,应该把this.state当成不可变变量。
    而使用this.setState方法,会触发异步修改状态,状态改变的同时,会重新执行一次willUpdate,render等流程。

代码执行顺序:

  1. <Clock /> 被传递给 ReactDOM.render() 时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state 。 我们稍后会更新此状态。
  2. React 然后调用 Clock 组件的 render() 方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配 Clock 的渲染输出。
  3. Clock 的输出插入到 DOM 中时,React 调用 componentDidMount() 生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick()
  4. 浏览器每秒钟调用 tick() 方法。 在其中,Clock 组件通过使用包含当前时间的对象调用 setState() 来调度UI更新。 通过调用 setState(),React 知道状态已经改变,并再次调用 render() 方法来确定屏幕上应当显示什么。 这一次,render() 方法中的 this.state.date 将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。
  5. 一旦 Clock 组件被从 DOM 中移除,React 会调用 componentWillUnmount() 这个钩子函数,定时器也就会被清除。

数据自顶向下流动

父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。

这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问

以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 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>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

这通常被称为自顶向下或单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。

为了表明所有组件都是真正隔离的,我们可以创建一个 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'));

也可以通过数组方式

let App=[ <Clock />,
      <Clock />,
      <Clock />];
ReactDOM.render(<div>{App}</div>, document.getElementById('example'));

六.React Props

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。

默认 Props

className.defaultProps指定了默认的属性和方法

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>菜鸟教程 React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>

<div id="example"></div>
<script type="text/babel">
class HelloMessage extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name},{this.props.date()}</h1>
    );
  }
}

HelloMessage.defaultProps = {
  name: 'Runoob',
  date:()=>{return new Date().toLocaleDateString();}
};

const element = <HelloMessage/>;

ReactDOM.render(
  element,
  document.getElementById('example')
);
</script>

</body>
</html>

State 和 Props

以下实例演示了如何在应用中组合使用 state 和 props 。我们可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据。

class WebSite extends React.Component {
  constructor() {
      super();
 
      this.state = {
        name: "菜鸟教程",
        site: "https://www.runoob"
      }
    }
  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/prop-types/15.6.1/prop-types.js"></script>

Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

以下实例创建一个 Mytitle 组件,属性 title 是必须的且是字符串,不然就是控制台报错

(菜鸟里面写的是会自动转换但是我没有试验出来)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>菜鸟教程 React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/prop-types/15.6.1/prop-types.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>

<div id="example"></div>
<script type="text/babel">
var title = "a";
// var title = 123;
class MyTitle extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.title} is :{typeof(this.props.title)}</h1>
    );
  }
}

MyTitle.propTypes = {
 title: PropTypes.string.isRequired,
};
ReactDOM.render(
    <MyTitle title={title} />,
    document.getElementById('example')
);
</script>

</body>
</html>

如果我换成数字表达式,控制台报错但是props值仍然会传递

更多验证器(dictionary)

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 事件处理

React 元素的事件处理和 DOM 元素类似。但是有一点语法上的不同:

  • React 事件绑定属性的命名采用驼峰式写法,而不是小写。

  • 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)

    HTML 通常写法是:

    <button onclick="activateLasers()">
      激活按钮
    </button>
    

    React 中写法为:

    <button onClick={activateLasers}>
      激活按钮
    </button>
    

在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确的使用 preventDefault

例如,通常我们在 HTML 中阻止链接默认打开一个新页面,可以这样写:

<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初始渲染监听器

使用 React 的时候通常你不需要使用 addEventListener 为一个已创建的 DOM 元素添加监听器。你仅仅需要在这个元素初始渲染的时候提供一个监听器。

当你使用 ES6 class 语法来定义一个组件的时候,事件处理器会成为类的一个方法。

例如,下面的 Toggle 组件渲染一个让用户切换开关状态的按钮:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>

<div id="example"></div>
<script type="text/babel">
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // 这边绑定是必要的,这样 `this` 才能在回调函数中使用
   this.handleClick = this.handleClick.bind(this);
	console.log(this);
  }

  handleClick() {
  console.log(this)
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }
  render() {
    return (
      <button onClick={this.handleClick}>
       {this.props.id }-{this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
ReactDOM.render(
 <div> <Toggle id="1"/><Toggle id="2"/></div>,
  
  document.getElementById('example')
);
</script>

</body>
</html>

两个容器不相互影响

关于jsx的this

你必须谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined。

这并不是 React 的特殊行为;它是函数如何在 JavaScript 中运行的一部分。通常情况下,如果你没有在方法后面添加 () ,例如onClick={this.handleClick},你应该为这个方法绑定 this。

如果使用 bind 让你很烦,这里有两种方式可以解决。如果你正在使用实验性的属性初始化器语法,你可以使用属性初始化器来正确的绑定回调函数:

        //如果不想用bind可以使用箭头函数,
        //  handleClick = () => {
        //     console.log('this is:', this);
	    //     this.setState(prevState => ({
        //     isToggleOn: !prevState.isToggleOn
        //     }));
        //     }
		//或者button处绑定<button onClick={(e) => this.handleClick(e)}>

每次 LoggingButton 渲染的时候都会创建一个不同的回调函数,这些组件可能会进行额外的重新渲染。通常建议在构造函数中绑定或使用属性初始化器语法来避免这类性能问题。(建议:bind或者箭头函数)

向事件处理程序传递参数

通常我们会为事件处理程序传递额外的参数。例如,若是 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 的方式,事件对象以及更多的参数将会被隐式的进行传递。

class Popper extends React.Component{
    constructor(){
        super();
        this.state = {name:'Hello world!'};
    }
    
    preventPop(name, e){    //事件对象e要放在最后
        //name=this.state.name
        //e被隐藏了是事件对象
        e.preventDefault();
        alert(name);
    }
    
    render(){
        return (
            <div>
                <p>hello</p>
                {/* 通过 bind() 方法传递参数。 */}
                <a href="https://reactjs" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
            </div>
        );
    }
}

八.React 条件渲染

在 React 中,你可以创建不同的组件来封装各种你需要的行为。然后还可以根据应用的状态变化只渲染其中的一部分。

React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。

元素变量

你可以使用变量来储存元素。它可以帮助你有条件的渲染组件的一部分,而输出的其他部分不会更改。

在下面的例子中,我们将要创建一个名为 LoginControl 的有状态的组件。

它会根据当前的状态来渲染 <LogoutButton /><LoginButton />,它也将渲染前面例子中的 <Greeting />

为方便观察,我将原文的bind都改成es6的箭头函数

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/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.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>
    );
  }
}
 let UserGreeting=(props)=> {
  return <h1>欢迎回来!</h1>;
}

 let GuestGreeting=(props)=> {
  return <h1>请先注册。</h1>;
}
let Greeting=(props)=> {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}
let 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 的条件运算符:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

阻止组件渲染

在极少数情况下,你可能希望隐藏组件,即使它被其他组件渲染。让 render 方法返回 null 而不是它的渲染结果即可实现。

比如:

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }
 
  return (
    <div className="warning">
      警告!
    </div>
  );
}

但是组件的 render 方法返回 null 并不会影响该组件生命周期方法的回调。

九.React 列表 & Keys

我们可以使用 JavaScript 的 map() 方法来创建列表

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
  <li>{numbers}</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

Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识

当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:

const todoItems = todos.map((todo, index) =>
  // 只有在没有确定的 id 时使用
  <li key={index}>
    {todo.text}
  </li>
);

一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

如果列表可以重新排序,我们不建议使用索引来进行排序,因为这会导致渲染变得很慢。

用keys提取组件

元素的 key 只有在它和它的兄弟节点对比时才有意义。

比方说,如果你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 **** 元素上,而不是放在 ListItem 组件中的 < ListItem /> 元素上。

key的正确使用方式

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 在他的兄弟元素之间应该唯一

数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。

key 会作为给 React 的提示,但不会传递给你的组件。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

Post 组件可以读出 props.id,但是不能读出 props.key。

在 jsx 中嵌入 map()

在上面的例子中,我们声明了一个单独的 listItems 变量并将其包含在 JSX 中

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
function ListItem(props) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('example')
);
</script>

</body>
</html>

十.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()**中实现了一些条件渲染逻辑

替换状态: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()**方法改变组件属性,触发组件重新渲染。

强制更新: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返回nullfalse时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。

判断组件挂载状态:isMounted(废除)

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

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

代替方式

componentDidMount() {
    this.mounted = true;
}

componentWillUnmount() {
    this.mounted = false;
}

十一.React 组件生命周期

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

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

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

***生命周期的方法***有:

  • componentWillMount 在渲染前调用,在客户端也在服务端。

  • componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。

    通过 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
    );
    
    
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
    可以在你确认不需要更新组件时使用。

  • componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。

  • componentWillUnmount在组件从 DOM 中移除之前立刻被调用。

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
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('加载前!')
  }
  componentDidMount() {
       console.log('加载完成')
  }
  componentWillReceiveProps(newProps) {
        console.log('接收 props后!')
  }
  shouldComponentUpdate(newProps, newState) {
  console.log("在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 ");
        return true;
  }
  componentWillUpdate(nextProps, nextState) {
        console.log('接收到新的props或者state,组件更新前');
  }
  componentDidUpdate(prevProps, prevState) {
        console.log('组件完成更新后!')
  }
  componentWillUnmount() {
         console.log('卸载前!')
  }
 
    render() {
      return (
        <div>
          <h3>{this.props.myNumber}</h3>
        </div>
      );
    }
}
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>

</body>
</html>

十二.React AJAX

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

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

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdn.staticfile/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
class UserGist extends React.Component {
  constructor(props) {
      super(props);
      this.state = {};//必须初始化
  }

  componentDidMount() {
    this.serverRequest = $.get(this.props.source, function (result) {
   // this.serverRequest = $.getJSON(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();//XMLHttpRequest.abort() 方法将终止该请求
  }
 
  render() {
    return (
      <div>
        {this.state.username} 用户最新的 Gist 共享地址:
        <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>
      </div>
    );
  }
}

ReactDOM.render(
    {/*<UserGist source="./gist.json" />,*/}
  <UserGist source="https://api.github/users/octocat/gists" />,
  document.getElementById('example')
);
</script>

</body>
</html>

十三.React 表单与事件

HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素生来就保留一些内部状态。

在 HTML 当中,像 <input>, <textarea>, <select> 这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。

一个简单的实例

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      
  }
 
  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')
);
</script>

</body>
</html>

上面的代码将渲染出一个值为 Hello Runoob! 的 input 元素,并通过 onChange 事件响应更新用户输入的值。

在父组件通过创建事件句柄 (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 Runoob!'};
      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 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')
);

多个表单

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2,
      value: 'coconut'
    };

    this.handleInputChange = this.handleInputChange.bind(this);
    this. handleSubmit = this.handleSubmit.bind(this);
  }

  handleInputChange(event) {
  console.log(this.state);
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }
  handleSubmit(event) {
    alert('the value is: ' + this.state.value);
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          是否离开:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
			<label>{this.state.isGoing.toString()}</label>
        </label>
        <br />
        <label>
          访客数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
			<label>{this.state.numberOfGuests}</label>
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
ReactDOM.render(
  <Reservation />,
  document.getElementById('example')
);

</script>

</body>
</html>

但是我觉得还是handleInputChange函数分开比较好,方便理顺思路,而且type类型也比较多

十四.React Refs

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();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
class MyComponent extends React.Component {
  handleClick() {
    // 使用原生的 DOM API 获取焦点
	console.log(this);
	this.refs.myDiv.style.background="red";
	this.refs.myInput.value="输入!!!";
    this.refs.myInput.focus();
	
  }
  render() {
    //  当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
    return (
      <div ref="myDiv">
        <input type="text" ref="myInput" />
        <input
		ref="myInputbt"
          type="button"
          value="点我输入框获取焦点"
          onClick={this.handleClick.bind(this)}
        />
      </div>
    );
  }
}
 
ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);
</script>

</body>
</html>

更多推荐

菜鸟教程react笔记【20200329】