[关闭]
@Dale-Lin 2019-03-20T13:11:36.000000Z 字数 5604 阅读 1391

React 概念

Reactjs


React 组件

React 允许将代码封装成 component,然后像插入普通 HTML 一样,在网页中插入这个组件。

React.createClass 方法用于生成一个组件类:

  1. var HelloMessage = React.createClass(
  2. render: function() {
  3. return <h1>Hello {this.props.name}</h1>;
  4. }
  5. );
  6. ReactDOM.render(
  7. <HelloMessage name="John" />,
  8. document.getElementById('example')
  9. );

上面代码中声明了组件类 HelloMessage 。在模板中插入 <HelloMessage /> 时(无子代的组件类可以使用自闭合标签),会自动生成该组件类的一个实例。所有组件类都必须有自己的 render 方法,用于输出组件。

组件类的第一个字母必须大写!
组件类只能包含一个顶层标签!

组件的用法和原生的 HTML 标签完全一致,可以任意加入属性。比如上述代码中,HelloMessage 组件的实例加入了一个 name 属性,值为 John。

组件的属性可以在组件 类 中的 this.props 对象中获取。如上例使用 this.props.name 获取了组件实例的 name 属性。

作为 JavaScript 保留字的属性有特殊写法:

this.props.children

this.props 对象的属性与组件的属性一一对应,例外的是 this.props.children 属性,它表示组件实例的所有子节点:

  1. var NotesList = React.createClass(
  2. render: function() {
  3. return (
  4. <ol>
  5. React.Children.map(this.props.children, function (child) {
  6. return <li>{child}</li>;
  7. })
  8. </ol>
  9. )
  10. }
  11. );
  12. ReactDOM.render(
  13. <NoteList>
  14. <span>hello</span>
  15. <span>world</span>
  16. </NoteList>,
  17. document.body
  18. );

上面代码的 NodeList 实例有两个子节点,都可以通过组件类中的 this.props.children 读取。

如果当前组件没有子节点,this.props.children 为 undefined;如果有一个子节点,数据类型是 object;如果有多个子节点,数据类型是 array。

上例使用了 React 提供的工具方法 React.Children.map(children, function[(thisArg)]) 来处理 this.props.children 。
使用这个方法可以遍历 this.props.children 子节点,不用考虑其数据类型。

事件处理

React 的事件类似 JavaScript 语法中的事件,要注意的是,事件处理函数返回 false 不会阻止事件的冒泡。应该合理使用 e.stopPropagation() 和 e.preventDefault() 来手动设置。

事件处理程序是公用的,事件对象会被复用,在事件处理程序结束后事件对象的所有属性会清除,不能通过异步方式访问事件:

  1. function onClick(event) {
  2. console.log(event); //nullified object.
  3. console.log(event.type); //"click"
  4. const event.type = event.type; //"click"
  5. setTimeout(function() {
  6. console.log(event.type); //null
  7. console.log(eventType); //"click"
  8. }, 0);
  9. //this.setState.clickEvent only contains null values
  10. this.setState({clickEvent: event});
  11. //can still export event properties
  12. this.setState({eventType: event.type);
  13. }

可以调用 event.persist() 将事件从公共池移出,从而异步地访问事件属性。

支持事件:

获取真实的 DOM 节点

组件是 virtual DOM 结构,只有插入文档以后才会变成真实的 DOM。
React 中,所有 DOM 变动都先在 virtual DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM 上(DOM diff)。

在组件类中声明 ref 属性用于获取真实的 DOM 节点:

  1. import React, { Component } from 'react';
  2. class Input extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.handleClick = this.handleClick.bind(this); //类的方法默认不绑定 this,为 undefined
  6. }
  7. handleClick(e) {
  8. this.refs.yourInputName.focus();
  9. }
  10. render() {
  11. return {
  12. <div>
  13. <input type="text" ref="yourInputName" />
  14. <input type="button" value="Focus the text input" onClick={this.handleClick} />
  15. </div>
  16. };
  17. }
  18. }

在 Input 组件的子节点中,第一个文本输入框用于获取用户的输入;第二个用于聚焦第一个文本框。Virtual DOM 是不能获取用户输入的,要拿到真实的 DOM 节点,在对应的 virtual DOM 元素上要设置一个 ref=[refName] ,其真实的 DOM 节点会保存在 this.refs.[refName] 中。

只有在 virtual DOM 插入文档后才会有该类的真实 DOM,这时才可以访问。

更好的用法

  1. <Component ref={(node) => {this.saveDomNode = node}}/>

如果 ref 属性是一个函数,将会把组件的 DOM 元素作为参数传给这个函数,从而可以获得其引用。

this.setState(updater/stateChange)

如果把组件看成一个函数,那么它接受了外部参数——props;内部参数为——state,返回一个 virtual DOM 的实现。

当组件实例与用户互动,this.setState 被调用来改变内部状态时,组件和其子组件会尝试重新渲染:

  1. import React, { Component } from 'react';
  2. class Counter extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.handleClick = this.handleClick.bind(this);
  6. this.state = { count: 0 };
  7. }
  8. handleClick(e) {
  9. e.preventDefault(); //使用该方法才能阻止默认行为
  10. this.setState({
  11. count: this.state.count + 1
  12. });
  13. }
  14. render() {
  15. return {
  16. <div>
  17. <p>{this.state.count}</p>
  18. <a href="#" onClick={this.handleClick}>Refresh</a>
  19. </div>
  20. };
  21. }
  22. }

参数可以是一个函数(updater):
(prevState, props) => stateChange
其中的 state 对应当前的 state,返回的是重新设置的 state。例如,利用原 state 和 props 设置:

  1. this.setState((prevState, props) => {
  2. return {count: prevState.count + props.step};
  3. });

也可以使用一个对象作为参数:
setState(stateChange)
这样将会把 stateChange 合并到更新的 state 中。

setState通过引发一次组件的更新过程来引发重新绘制

setState 方法调用引起的 React 组件更新四个生命周期函数:

比起修改 props 引发的生命周期少一个 componentWillReceiveProps。
只有 render 调用时,state 才会更新。

React 生命周期

React 组件的生命周期分为两类:

组件的挂载和卸载过程

组件的挂载又称组件的初始化,有两个生命周期方法:

数据更新过程

更新过程指父组件向下传递 props 或组件自身执行 setState() 方法时发生的一系列动作。

如果组件自身的 state 更新了,会依次执行:

shouldComponentUpdate() 是一个特别的方法,它接收需要更新的 props 和 state,可以在内部进行判断,让组件在需要更新的时候进行更新。当方法返回 false 的时候,组件不再向下执行生命周期方法。

默认情况下组件会将更新 props 节点的所有子节点重新渲染,因为 shouldComponentUpdate() 方法返回 true。

无状态组件每次都会重新渲染。

componentWillUpdate(nextProps, nextState) 在渲染前,提供需要更新的 props 和 state;componentDidUpdate(prevProps, prevState) 在渲染后,提供更新前的 props 和 state,。

如果组件是由父组件更新 props 而更新的,那么在 shouldComponentUpdate() 之前会先执行 componentWillReceiveProps(nextProps)。
此方法可以作为 React 组件在 props 传入后,渲染之前 setState() 而不二次渲染的机会。

整体流程

新生命周期

static getDerivedStateFromProps(nextProps, prevState)

用该方法替换 componentsWillReceiveProps。
返回值是包含要更新的 state 对象的:

  1. static getDerivedStateFromProps(nextProps, prevState) {
  2. if (nextProps.value !== prevState.value) {
  3. return {
  4. value: nextProps.value,
  5. }
  6. }
  7. return null,
  8. }

React 与 DOM

ReactDOM

在顶层组件以及由于 React 模型所限而不得不操作 DOM 的时候,需要使用 ReactDOM。
DOM 真正被添加到 HTML 中的生命周期方法是 componentDidMount 和 componentDidUpdate ,在这两个方法中可以使用以下两种方法获取真正的 DOM 元素。

要严格限制 DOM 操作场景!

ref

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注