常用API

React

React 是 React 庫的頂層 API,可以使用以下幾個(gè)方式引入

  • 使用 script 標(biāo)簽引入的組件庫,全局有一個(gè) React 的對(duì)象

  • 使用 ES6 和 npm 的時(shí)候,可以通過編寫 import React from 'react' 來進(jìn)行引入

  • ES5 與 npm 時(shí),則可以通過編寫 var React = require('react') 來引入它們

React.memo

const MyComponent = React.memo(function MyComponent(props) {
  /* 使用 props 渲染 */
});

如果你的組件在相同 props 的情況下渲染相同的結(jié)果,那么你可以通過將其包裝在 React.memo 中調(diào)用

React.memo 僅檢查 props 變更。

如果函數(shù)組件被 React.memo 包裹,且其實(shí)現(xiàn)中擁有 useState,useReducer 或 useContext 的 Hook,當(dāng) state 或 context 發(fā)生變化時(shí),它仍會(huì)重新渲染。

默認(rèn)情況下其只會(huì)對(duì)復(fù)雜對(duì)象做淺層對(duì)比,如果你想要控制對(duì)比過程,那么請將自定義的比較函數(shù)通過第二個(gè)參數(shù)傳入來實(shí)現(xiàn)。

function MyComponent(props) {
  /* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
  /*
  如果把 nextProps 傳入 render 方法的返回結(jié)果與
  將 prevProps 傳入 render 方法的返回結(jié)果一致則返回 true,
  否則返回 false
  */
}
export default React.memo(MyComponent, areEqual);

React.Children

React.Children 提供了用于處理 this.props.children 不透明數(shù)據(jù)結(jié)構(gòu)的實(shí)用方法。

React.forwardRef

React.forwardRef 會(huì)創(chuàng)建一個(gè) React 組件,這個(gè)組件能夠?qū)⑵浣邮艿?ref 屬性轉(zhuǎn)發(fā)到其組件樹下的另一個(gè)組件中。

在以下兩種場景中特別有用:

  • 轉(zhuǎn)發(fā) refs 到 DOM 組件

  • 在高階組件中轉(zhuǎn)發(fā) refs

React.forwardRef 接受渲染函數(shù)作為參數(shù)。React 將使用 props 和 ref 作為參數(shù)來調(diào)用此函數(shù)。此函數(shù)應(yīng)返回 React 節(jié)點(diǎn)。

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

React.Component

class 組件中必須定義 render 方法,其他都是可選的

常用的生命周期方法

render()

render() 函數(shù)應(yīng)該為純函數(shù),這意味著在不修改組件 state 的情況下,每次調(diào)用時(shí)都返回相同的結(jié)果,并且它不會(huì)直接與瀏覽器交互。

如需與瀏覽器進(jìn)行交互,請?jiān)?componentDidMount() 或其他生命周期方法中執(zhí)行你的操作。

constuctor(props)

如果不初始化 state 或不進(jìn)行方法綁定,則不需要為 React 組件實(shí)現(xiàn)構(gòu)造函數(shù)。

在 constructor() 函數(shù)中不要調(diào)用 setState() 方法。如果你的組件需要使用內(nèi)部 state,請直接在構(gòu)造函數(shù)中為 this.state 賦值初始 state

componentDidMount()

componentDidMount() 會(huì)在組件掛載后(插入 DOM 樹中)立即調(diào)用。依賴于 DOM 節(jié)點(diǎn)的初始化應(yīng)該放在這里。如需通過網(wǎng)絡(luò)請求獲取數(shù)據(jù),此處是實(shí)例化請求的好地方。

你可以在 componentDidMount() 里直接調(diào)用 setState()。它將觸發(fā)額外渲染,但此渲染會(huì)發(fā)生在瀏覽器更新屏幕之前。如此保證了即使在 render() 兩次調(diào)用的情況下,用戶也不會(huì)看到中間狀態(tài)。

componentDidUpdate(prevProps, prevState, snapshot)

你也可以在 componentDidUpdate() 中直接調(diào)用 setState(),但請注意它必須被包裹在一個(gè)條件語句里,否則會(huì)導(dǎo)致死循環(huán)。

它還會(huì)導(dǎo)致額外的重新渲染,雖然用戶不可見,但會(huì)影響組件性能。 變化更新到 DOM 但是渲染到頁面之前

componentWillUnmount()

componentWillUnmount() 會(huì)在組件卸載及銷毀之前直接調(diào)用。在此方法中執(zhí)行必要的清理操作

不常用的生命周期方法

shouldComponentUpdate(nextProps, nextState)

根據(jù) shouldComponentUpdate() 的返回值,判斷 React 組件的輸出是否受當(dāng)前 state 或 props 更改的影響。默認(rèn)行為是 state 每次發(fā)生變化組件都會(huì)重新渲染。

  • true - 重新渲染

  • false - 不重新渲染(會(huì)跳過當(dāng)前組件以及其子組件的渲染,類似于 Angular 的 ChangeDetectionStrategy.OnPush)

如果你需要手動(dòng)編寫此函數(shù),可以將 this.props 與 nextProps 以及 this.state 與 nextState 進(jìn)行比較,并返回 false 以告知 React 可以跳過更新。返回 false 并不會(huì)阻止子組件在 state 更改時(shí)重新渲染。

static getDerivedStateFromProps(props, state)

會(huì)在 shouldComponentUpdate 之前調(diào)用。返回一個(gè)對(duì)象來更新 state,如果返回 null 則不更新任何內(nèi)容。

此方法無權(quán)訪問組件實(shí)例

getSnapshotBeforeUpdate(prevProps, prevState)

在 render 之后,componentDidUpdate 之前調(diào)用

Error Boundary

static getDerivedStateFromError(error)

此生命周期會(huì)在后代組件拋出錯(cuò)誤后被調(diào)用。 它將拋出的錯(cuò)誤作為參數(shù),并返回一個(gè)值以更新 state

getDerivedStateFromError() 會(huì)在渲染階段調(diào)用,因此不允許出現(xiàn)副作用。 如遇此類情況,請改用 componentDidCatch()。

componentDidCatch(error, info)

componentDidCatch() 會(huì)在“提交”階段被調(diào)用,因此允許執(zhí)行副作用。

其他 API

setState(updater, [callback])

setState() 將對(duì)組件 state 的更改排入隊(duì)列,并通知 React 需要使用更新后的 state 重新渲染此組件及其子組件。

React 會(huì)延遲調(diào)用它,然后通過一次傳遞更新多個(gè)組件。React 并不會(huì)保證 state 的變更會(huì)立即生效。

setState() 并不總是立即更新組件。它會(huì)批量推遲更新。

  • 請使用 componentDidUpdate 或者 setState 的回調(diào)函數(shù)(setState(updater, callback))來獲取最新的 state,這兩種方式都可以保證在應(yīng)用更新后觸發(fā)。

  • 基于之前的 state 來設(shè)置當(dāng)前的 state,可以給 setState 的第一個(gè)參數(shù)傳遞一個(gè)函數(shù),函數(shù)有兩個(gè)參數(shù)(state 和 props)都代表最新的 state 和 props。updater 函數(shù)中接收的 state 和 props 都保證為最新。updater 的返回值會(huì)與 state 進(jìn)行淺合并。

React 會(huì)按照調(diào)用 setState 的順序更新狀態(tài)

無論您在 React 事件處理程序 setState()中調(diào)用多少組件,它們都只會(huì)在事件結(jié)束時(shí)產(chǎn)生一次重新渲染。

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { a: false, b: false };
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.a.toString() + " " + this.state.b.toString()}
      </button>
    );
  }

  handleClick = () => {
    // 點(diǎn)擊按鈕之后a、b都是true
    this.setState({ a: true });
    this.setState({ b: true });
  };
}

解釋一下:

setState()調(diào)用都發(fā)生在 React 事件處理程序中。因此,它們總是在事件結(jié)束時(shí)一起刷新(并且您看不到中間狀態(tài))

更新總是按照它們發(fā)生的順序進(jìn)行淺層合并。所以如果第一次更新是{a: 10},第二次是{b: 20},第三次是{a: 30},渲染狀態(tài)將是{a: 30, b: 20}。對(duì)同一狀態(tài)鍵的最新更新(例如 a 在我的示例中)總是“獲勝”。

但是在下面的這種情況中,當(dāng)一個(gè)新的 state 依賴于之前的 state 的時(shí)候,結(jié)果可能與我們想象的不一致

// assuming this.state = { value: 0 };
this.setState({ value: this.state.value + 1 });
this.setState({ value: this.state.value + 1 });
this.setState({ value: this.state.value + 1 });
// 最后 this.state.value 為 1

此時(shí)推薦使用韓式

// assuming this.state = { value: 0 };
this.setState(state => ({ value: state.value + 1 }));
this.setState(state => ({ value: state.value + 1 }));
this.setState(state => ({ value: state.value + 1 }));
// 最后 this.state.value 為 3
  1. 何時(shí)以及為什么 setState 會(huì)批量執(zhí)行?
  • 何時(shí):setState 的異步更新是在 React 的生命周期函數(shù)以及 React 的事件處理函數(shù)中,除此之外的場景(定時(shí)器、ajax 請求、Promise 中、addEventListener 綁定的事件處理函數(shù)中都是同步執(zhí)行的)

  • 為什么:優(yōu)化性能

實(shí)例屬性

state

組件中的 state 包含了隨時(shí)可能發(fā)生變化的數(shù)據(jù)。state 由用戶自定義,它是一個(gè)普通 JavaScript 對(duì)象。

如果某些值未用于渲染或數(shù)據(jù)流(例如,計(jì)時(shí)器 ID),則不必將其設(shè)置為 state。此類值可以在組件實(shí)例上定義。

永遠(yuǎn)不要直接改變 this.state,因?yàn)楹罄m(xù)調(diào)用的 setState() 可能會(huì)替換掉你的改變。請把 this.state 看作是不可變的。

ReactDOM

  • script 標(biāo)簽引入的,全局有一個(gè) ReactDOM

  • ES6 和 npm,通過 import ReactDOM form 'react-dom' 來使用 ReactDOM

  • 使用 npm 和 ES5,你可以用 var ReactDOM = require('react-dom')。

ReactDOM.render(element, container[, callback])

在提供的 container 里渲染一個(gè) React 元素,并返回對(duì)該組件的引用

ReactDOM.render() 不會(huì)修改容器節(jié)點(diǎn)(只會(huì)修改容器的子節(jié)點(diǎn))。可以在不覆蓋現(xiàn)有子節(jié)點(diǎn)的情況下,將組件插入已有的 DOM 節(jié)點(diǎn)中。

ReactDOM.unmountComponentAtNode(container)

從 DOM 中卸載組件,會(huì)將其事件處理器(event handlers)和 state 一并清除。如果指定容器上沒有對(duì)應(yīng)已掛載的組件,這個(gè)函數(shù)什么也不會(huì)做。如果組件被移除將會(huì)返回 true,如果沒有組件可被移除將會(huì)返回 false。

DOM 元素

React 實(shí)現(xiàn)了一套獨(dú)立于瀏覽器的 DOM 系統(tǒng),兼顧了性能和跨瀏覽器的兼容性。

屬性差異

checked

當(dāng) <input> 組件的 type 類型為 checkbox 或 radio 時(shí),組件支持 checked 屬性。你可以使用它來設(shè)置組件是否被選中。這對(duì)于構(gòu)建受控組件很有幫助。而 defaultChecked 則是非受控組件的屬性,用于設(shè)置組件首次掛載時(shí)是否被選中。

className

className 屬性用于指定 CSS 的 class

React 中使用 Web Components(這是一種不常見的使用方式),請使用 class 屬性代替。

dangerouslySetInnerHTML

類似于 HTML 中的 innerHTML 屬性

可以直接在 React 中設(shè)置 HTML,但當(dāng)你想設(shè)置 dangerouslySetInnerHTML 時(shí),需要向其傳遞包含 key 為 __html 的對(duì)象,以此來警示你

htmlFor

由于 for 在 JavaScript 中是保留字,所以 React 元素中使用了 htmlFor 來代替。

onChange

onChange 事件與預(yù)期行為一致:每當(dāng)表單字段變化時(shí),該事件都會(huì)被觸發(fā)。

selected

如果要將 <option> 標(biāo)記為已選中狀態(tài),請?jiān)?select 的 value 中引用該選項(xiàng)的值。

style

style 接受一個(gè)采用小駝峰命名屬性的 JavaScript 對(duì)象,而不是 CSS 字符串。

const divStyle = {
  color: "blue",
  backgroundImage: "url(" + imgUrl + ")"
};

function HelloWorldComponent() {
  return <div style={divStyle}>Hello World!</div>;
}

React 會(huì)自動(dòng)添加 ”px” 后綴到內(nèi)聯(lián)樣式為數(shù)字的屬性后。如需使用 ”px” 以外的單位,請將此值設(shè)為數(shù)字與所需單位組成的字符串。

value

<input>、<select><textarea> 組件支持 value 屬性。你可以使用它為組件設(shè)置 value。這對(duì)于構(gòu)建受控組件是非常有幫助。defaultValue 屬性對(duì)應(yīng)的是非受控組件的屬性,用于設(shè)置組件第一次掛載時(shí)的 value。

合成事件

SyntheticEvent 實(shí)例將被傳遞給你的事件處理函數(shù),它是瀏覽器的原生事件的跨瀏覽器包裝器。除兼容所有瀏覽器外,它還擁有和瀏覽器原生事件相同的接口,包括 stopPropagation() 和 preventDefault()。

使用 nativeEvent 屬性來獲取瀏覽器的底層事件。

事件處理函數(shù)在冒泡階段被觸發(fā)。如需注冊捕獲階段的事件處理函數(shù),則應(yīng)為事件名添加 Capture。例如,處理捕獲階段的點(diǎn)擊事件請使用 onClickCapture,而不是 onClick。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容