React 16.3

Context API

見 [React 16_3 | Context](/React 16.3_Context.md)

createRef API

React.createRef() 用以簡化 ref 綁定

  • 實際的 DOM/ReactComponent 為 aRef.current

  • 仍支援 callback ref (function 寫法) 綁定。

  • 適用於綠葉角色的元件設計,例如:EUButton(、EUInput)。

class ExampleInput extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }
  
  /** @override */
  componentDidMount() {
    const DOM = this.inputRef.current
  }
  
  /** @override */
  render() {
    return <input ref={this.inputRef}/>
  }
}

forwardRef API

把 ReactComponent 內的 ref 提供給父元件,做為自身的 Ref。

  • 配合 HOCs 設計使用。
const EUButtonBase = React.forwardRef((props, ref) => (
  <props.type
    className={this.props.className}
    ref={ref}
  >
    	{props.children}
  </props.type>
))

class EUButton extends React.Component {
  constructor(props) {
    super(props);
    this.ref = React.createRef();
  }
    
  render() {
    return (
      <EUButtonBase
        className="eu-button"
        ref={this.ref}
      >
        <i className={`eu-icon ${this.props.icon}`}/>
        <span className="eu-button_content">{this.props.name}</span>
      </EUButtonBase>
    );
  }
}

Lifecycle API

graph TB
	0(Init)-->A(static getDerivedStateFromProps)
	A-->B(componentDidMount)
	A-->C(shouldComponentUpdate)
	C-->D(getSnapshotBeforeUpdate)
	D-->E(componentDidUpdate)

既有 API 修改

16.3 版本還是可以使用原本的 API

  • componentWillMountUNSAFE_componentWillMount
  • componentWillReceivePropsUNSAFE_componentWillReceiveProps
  • componentWillUpdateUNSAFE_componentWillUpdate

getDerivedStateFromProps API

  • static getDerivedStateFromProps(props, state):nextState
  • 為 static,需回傳作為下個 state 的 Object
  • 元件沒有 state 時,在 dev 版的 library 在 console 會提示。
class Example extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // ...
  }
}

getSnapshotBeforeUpdate API

  • componentDidUpdate 前執行

  • 回傳值作為 componentDidUpdate 第三個參數使用;如無需要,則回傳 null

  • 使用範例:判斷列表是否增加內容;如果增加,則在渲染前將捲軸高度調至更新前的狀態,避免捲軸位置更動。

    class ScrollingList extends React.Component {
      constructor(props) {
        super(props);
        this.listRef = React.createRef();
      }
    
      getSnapshotBeforeUpdate(prevProps, prevState) {
        // Are we adding new items to the list?
        // Capture the scroll position so we can adjust scroll later.
        if (prevProps.list.length < this.props.list.length) {
          const list = this.listRef.current;
          return list.scrollHeight - list.scrollTop;
        }
        return null;
      }
    
      componentDidUpdate(prevProps, prevState, snapshot) {
        // If we have a snapshot value, we've just added new items.
        // Adjust scroll so these new items don't push the old ones out of view.
        // (snapshot here is the value returned from getSnapshotBeforeUpdate)
        if (snapshot ! null) {
          const list = this.listRef.current;
          list.scrollTop = list.scrollHeight - snapshot;
        }
      }
    
      render() {
        return (
          <div ref={this.listRef}>{/* ...contents... */}</div>
        );
      }
    }
    

Lifecycle 設計 Tips

  1. state initializing 放在 constructor
  2. 獲取外部數據 (加載數據) 放到 componentDidMountcomponentDidUpdate API

Strict Mode

  • 幫忙檢查
    • 警告不安全的 lifecycle (棄用的 API)
    • 警告 string ref 的使用
    • 偵測預期外的 side effect (文長略)
    • 警告舊版的 Context API 使用
import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <!-- 僅檢查 React.StrictMode 內的元件 -->
      <React.StrictMode>
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>
      <Footer />
    </div>
  );
}

Change Log

僅節錄目前已使用的部分

DOM

  • Fix minor DOM input bugs in IE and Safari

  • Fix a crash when the input type changes from some other types to text

  • Fix onMouseEnter and onMouseLeave firing on wrong elements

  • Correctly detect Ctrl + Enter in onKeyPress in more browsers

Library

  • Warn when defining a non-existent componentDidReceiveProps method
  • Warn about function child no more than once
  • Warn about nested updates no more than once
  • Add support for portals in React.Children utilities
  • React.is() Library