React 16 新特性使用总结

本文深入探讨React16.5版本中引入的重要新特性,包括生命周期函数的改进,如getDerivedStateFromProps、getSnapshotBeforeUpdate及componentDidCatch,以及Context API和Portal的使用方法。此外,还介绍了React.createRef的用法,帮助开发者更好地理解并应用这些新特性。

从React 16.0开始,React引入了一下新的特性(组件、API、生命周期函数)。从15.X升级到16.X是一种增强式的升级即之前的用法在新版上保持有效,基本是平滑的升级,但是随着React 16.5的发布,新特性基本已经完善和固定下来,为了享受新版本带来的更高效率架构和更规范的开发流程,现在是时候使用上React ^16.0 的新特性进行代码重构。

我直接使用了React 16.5,具体请查看React 更新日志以下是几个常用的新特性,每个特性都从与之前的比较和实例来说明:

一、生命周期函数

生命周期函数的改动有两个方面

新增:

static getDerivedStateFromProps(nextProps, prevState) getSnapshotBeforeUpdate(prevProps, prevState) componentDidCatch(error, info)

不安全:

UNSAFE_componentWillMount(nextProps, nextState) UNSAFE_componentWillReceiveProps(nextProps) UNSAFE_componentWillUpdate(nextProps, nextState)

在16.X版本中依然可以使用不安全的周期函数(UNSAFE_前缀可加可不加),用法也和之前的一样。但是如果使用了新增的周期函数就不能同时使用不安全的周期函数,否则会报错并且不安全的周期函数不会被执行

使用新增的周期函数的执行顺序还是按照阶段来说明:

装载阶段

constructor -> getDerivedStateFromProps -> render -> componentDidMount

更新阶段

getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate

卸载阶段

componenWillUnMount

新增的生命周期函数

getDerivedStateFromProps周期函数的作用是根据props初始化或更新state,有两个参数分别是nextProps(本次渲染的props)和prevState(当前组件的state),判断nextProps和prevState对应的属性是否相同,返回需要更改的state。

React 15.X 初始化和更新分别写在constructor和componentWillReceiveProps.
class Parent extends Component{
    render(){
        return (
        <Child age={18} />
        )
    }
}
class Child extends Components{
    constructor(props){
        super(props);
        this.state = {
            age: this.props.age //装载阶段初始化state
        }
    }
    componentWillReceiveProps(nextProps){
        if(nextProps.age !== this.state.age){
            this.setState({
                age: nextProps.age
            }) // 修改state
        }
    }
    render(){...}
}

React 16.5 写在getDerivedStateFromProps即可
class Child extends Component{
    constructor(props){
        super(props);
        this.state = {
            age: ''
        }
    }
    static getDerivedStateFromProps(nextProps,prevState){
        if(nextProps.age !== prevState.age){
            return {
                age: nextProps.age
            }
        }
        return null;
    }
    render(){...}
}
复制代码

getSnapshotBeforeUpdate作用是替代componentWillUpdate,有两个参数分别是prevProps(未更新前的props)和prevState(未更新前的state)。最大的区别是它放在了render函数后执行,为将来的Fiber架构做准备;还有的区别是componetWillUpdate的参数是nextProps(本次更新的props)和nextState(本次更新的state),在转换时需要注意。

列表项数目改变时scroll到最后一条
 getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.list.length !== this.props.list.length) {
      const list = this.listRef.current //dom渲染前的列表元素ref
      return list.scrollHeight - list.scrollTop
    }
    return null
  }
    
  componentDidUpdate(prevProps, prevState, snapshot) {
    // snapshot 是getSnapshotBeforeUpdate返回的偏移量
    if (snapshot !== null) {
      const list = this.listRef.current //dom渲染后的列表元素ref
      list.scrollTop = list.scrollHeight - snapshot
    }
  }

复制代码

componentDidCatch React组件发生错误时的处理逻辑,调用第三方的错误监听服务。

二、Context

使用Context 主要是解决props向多层嵌套的子组件传递的问题,原理是定义了一个全局对象。新的Context的使用方法跟旧的有很大差别

// React 15.x需要自己开发定义提供 Context的父组件,然后用这个父组件包裹嵌套多层的子组件。
class Provider extends Component {
    getChildContext(){
        return {
            age: 18
        }
    }
    render() {
        return this.props.children;
    }
}
Provider.childContextTypes = {
    age: PropTypes.number
};
// 子组件
class Child extends Component {
    constructor(props,context) { 
        super(props,context); //super 带上context 参数
    }
    render(){
        const {age} = this.context; //使用this.context访问
        ...
    }
}
Child.contextTypes = {
    age: PropTypes.number
};

// React 16.5 使用 React.createContext()
const MyContext = React.createContext();
// 使用 MyContext.Provider 包裹子组件
<MyContext.Provider value={{age: 18}}>
    <Child />
</MyContext.Provider>
//子组件使用 MyContext.Consumer获得 Context
class Child extends Component {
    render(){
       return (
       <MyContext.Consumer>
            {(context) => {
                const {age} = context;
                return ...
            }}
       </MyContext.Consumer>
       )
    }
}

复制代码
三、Portal 和 Refs

Portal 是React 16 的全新特性,可以将组件渲染到非根节点其他 DOM 节点上,因为之前版本没有这个功能,所以使用场景需要逐步发掘。用法是使用ReactDOM.createPortal(component, domNode) component是要渲染的组件,domNode是挂载的dom节点。

React 16 使用React.createRef 创建Ref对象,以下是使用的区别:

// React 15.X
class Parent extends Component {
    getChildRef(ref){
        this.myRef = ref;
    }
    render() {
        <Child childRef={this.getChildRef} />
    }
}
class Child extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    return <div ref={this.props.childRef} />
  }
}

// React 16.5
class Parent extends Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }
  render() {
      return <Child ref={this.myRef} />
  }
}

const Child = React.forwardRef((props, ref) =>  <div ref={ref} />);

复制代码

转载于:https://juejin.im/post/5bae1c76f265da0a872668d4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值