react 升级到 16.2.0 记录

React 升级到 16.2.0 使用记录

说明

最新中文官方文档

1. 函数定义组件与类定义组件

针对有复杂状态或者有多个事件处理函数的组件尽量使用 ‘类定义组件’;而对于简单的展示型组件,可以使用函数定义组件,减少代码量,函数的第一个参数是传入的 props

    // 类定义组件
    import React, { Component } from 'react';
    import {withRouter} from 'react-router-dom';

    import '../../scss/home.scss';

    @withRouter
    export default class TestCom extends Component {
       constructor(props) {
          super(props);
       }
       handleClick = () => {
          // withRouter 使组件获得了 location history match 三个属性
          this.props.history.push({
             pathname: '/home',
             search: '?name=testname'
          });
       }
       render() {
          console.log(this.props);

          return (
             <div className="test-container">
                this is Test Page
                <button onClick={this.handleClick}>点击回到 home page</button>
             </div>
          );
       }
    }
    // 函数定义组件,不能访问 this 
    import React from 'react';
    import MemberItems from './MemberItems';

    /*
       纯展示型组件可以使用函数式组件,传入的第一个参数是 props ,在这里不能访问 this
    */
    const MemberList = ({memberList}) => (
       <div className="member-list-wrap">
          <ul className="member-list">
             <MemberItems memberList={memberList}/>
          </ul>
       </div>
    );

    export default MemberList;

2. 不用于视觉输出的东西的存储

如果需要存储不用于视觉输出的东西,可以直接添加到类中,而不是存储在状态中

如果你不在 render() 中使用某些东西,它就不应该在状态 state 中

    export default class TestCom extends Component {
       constructor(props) {
          super(props);
          this.state = {count: 0};
       }
       tick = () => {
          this.setState({count: this.state.count + 1});
       }
       // 定时器就是一个不需要视觉输出的,但是却需要绑定在组件上,这个时候直接挂在到 this 上即可
       componentDidMount() {
          this.countTimer = setInterval(() => {
             this.tick();
          }, 1000)
       }
       componentWillUnmount() {
          clearInterval(this.countTimer);  
       }
       render() {
          return (
             <div className="test-container">{this.state.count}</div>
          );
       }
    }

3. this.setState() 可以接收一个函数来处理异步的数据更新

this.setState({data: ''}) 函数可以传入一个对象用于更新 state ,但是如果有多个 setState() 调用,React 会将多个setState() 调用合并成一个调用来提高性能,也就是说更新可能是异步的

   handleClick = () => {
    // 只有最后一个 setState() 更新的 state 有效
      this.setState({count: this.state.count + 10});
      this.setState({count: this.state.count * 2});
      this.setState({count: this.state.count + 22});
   }

this.setState((prevState, props) => {}) 允许传入一个函数作为参数,处理异步的更新,函数接收 prevState (先前的状态) 和 props (此次更新应用时的 props) 两个参数,函数需要返回一个计算后的数据对象

    // 三个更新会依次执行,只触发一次 update ,也就是重新 render 一次
   handleClick = () => {
      this.setState((prevState) => ({count: prevState.count + 10}));
      this.setState((prevState) => ({count: prevState.count * 2}));
      this.setState((prevState) => ({count: prevState.count + 22}));
   }

4. 事件处理函数写法

  • 使用 es6 箭头函数代替 .bind(this)
  • 需要传递参数的事件处理函数 还是使用 .bind(this, props) 绑定在组件上

这里只是使用习惯

export default class TestCom extends Component {
   constructor(props) {
      super(props);
   }
   // 使用箭头函数,自动绑定 this 
   handleClick = () => {
        console.log(this);
   }
   render() {
      return (
         <button onClick={this.handleClick}>点击</button>
      );
   }
}

export default class TestCom extends Component {
   constructor(props) {
      super(props);
   }
   handleClick (test, e) {
        console.log(this);
   }
   render() {
       // 如果传递参数,还是在这里通过 bind ,函数处理默认接收最后一个参数是 event 对象
      return (
         <button onClick={this.handleClick.bind(this, 'test')}>点击</button>
      );
   }
}

5. 数字 0 会被渲染

false、null、undefined 和 true 都是有效的子代,但它们不会直接被渲染,但是 JavaScript 中的一些 “falsy” 值(比如数字0),它们依然会被渲染,因此如果不想渲染要确保 && 前面的表达式始终为布尔值

    // count = 0 时渲染为 0
    {count && <p>has count num: {count}</p>}
    // count = 0 时不渲染 
    {!!count && <p>has count num: {count}</p>}

6. Refs 使用

1. 上一个版本的 refs 使用方法,还是有效的

    // 子组件
    export default class TestForm extends PureComponent {
       constructor(props) {
          super(props);
          this.state = {name: 'test name'}
       }
       getName = () => {
          return this.state.name;
       }
       render() {
          return <div></div>;
       }
    }
    // 父组件
    export default class TestCom extends Component {
       constructor(props) {
          super(props);
       }
       componentDidMount() {
          console.log(this.refs.test);
          // 这里还是能够通过 this.refs 获取对应的组件并且使用组件的方法
          const name = this.refs.test.getName();
          console.log(name);
       }
       render() {
          const {count} = this.state;
          return (
             <div className="test-container">
                <TestChild ref="test"/>
             </div>
          );
       }
    }

2. refs 新的使用方法(官方推荐方法)

ref 属性接收一个回调函数,它在组件被加载或卸载时立刻执行,这个回调函数接收了底层的 DOM 元素作为参数,可以将其存储到当前实例上(this 上)

不仅可以在 html 标签上,也可以将其使用在类组件上,且仅限 class 声明的类组件

    // 子组件
    export default class TestForm extends PureComponent {
       constructor(props) {
          super(props);
          this.state = {name: 'test name'}
       }
       getName = () => {
          return this.state.name;
       }
       render() {
          return <div></div>;
       }
    }
    // 父组件
    export default class TestCom extends Component {
       constructor(props) {
          super(props);
       }
       componentDidMount() {
          console.log(this.TestForm);
          // 直接从实例上获取
          const name = this.TestForm.getName();
          console.log(name);
       }
       render() {
          const {count} = this.state;
          // ref 值为回调函数,将组件实例挂在到 this 上
          return (
             <div className="test-container">
                <TestForm ref={TestForm => this.TestForm = TestForm}/>
             </div>
          );
       }
    }

7. 避免重复渲染

  • 通过 shouldComponentUpdate 生命周期函数提升速度
  • 通过插件 pure-render-decorator 插件实现
  • 通过继承 React 提供的 PureComponent 组件实现
    class CounterButton extends React.PureComponent {
      constructor(props) {
        super(props);
      }

      render() {
        return (
          <button> click </button>
        );
      }
    }

8. render 方法 可以返回一个数组

react 16 开始 render 可以返回一个数组

export default class MemberItems extends PureComponent {
   constructor(props) {
      super(props);
   }
   render() {
      const memberList = this.props.memberList;
    // map 方法的返回值是一个数组
      return memberList.map((item, i) => {
         return (
            <li key={i}>
               <p>name:<span>{item.name}</span></p>
               <p>tel:<span>{item.tel}</span></p>
            </li>
         );
      });
   }
}

9. Fragments 聚合子元素

Fragments 可以让你聚合一个子元素列表,并且不在DOM中增加额外节点, Fragments 看起来像空的 JSX 标签

render() {
    return (
        <>
            <ChildA />
            <ChildB />
            <ChildC />
        </>
    );
}
// 更清晰的写法 用来添加 key 
render() {
    return (
        <React.Fragment>
            <td>Hello</td>
            <td>World</td>
        </React.Fragment>
    );
}

10. 使用 Portals 将子节点渲染到父组件以外的 DOM 节点

import {PureComponent} from 'react';
import ReactDom from 'react-dom';

export default class TestForm extends PureComponent {
   constructor(props) {
      super(props);
      this.el = document.querySelector('body');
   }
   // 直接插入到 body 中
   render() {
      return ReactDom.createPortal(
         this.props.children,
         this.el
      )
   }
}

11. 错误边界

部分 UI 的异常不应该破坏了整个应用,这是使用错误边界的初衷,错误边界可以捕获其子组件树 JavaScript 异常,记录错误并展示一个回退的 UI 的 React 组件,而不是整个组件树的异常。一下是官网示例

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }

      componentDidCatch(error, info) {
        // Display fallback UI
        this.setState({ hasError: true });
        // You can also log the error to an error reporting service
        logErrorToMyService(error, info);
      }

      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }

    // 组件中使用
    <ErrorBoundary>
      <MyWidget />
    </ErrorBoundary>

猜你喜欢

转载自blog.csdn.net/mjzhang1993/article/details/79025721
今日推荐