寫 React Components 該注意的6個地方與技巧
在寫 React 的過程中,發現有一些小地方是我們可以多了解、多注意的,因此記錄與分享。
一、SetState 傳遞 Function
在 React 官方文件直接寫到,State 的更新是非同步的,通常會 batch 更新,因此直接依賴之前的 state 來更新 State 可能會出錯。
不好的寫法:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
較好的寫法:
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
二、使用 PureComponent
在適當的時機下,透過 PureComponent 可以提升效能,這是由於繼承 React.PureComponent 在shouldComponentUpdate
預設實作 shadow compare 新的 props & state 與舊的 props & state,如果兩者相同就會回傳 false,不 re-render component。
class Button extends React.PureComponent {
constructor(props) {
super(props);
this.state = {count: 1};
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
三、撰寫 Pure Render Function
Pure render 是指 render function 是 pure function,以及相同的 Input 應該產生相同的 output。
而在 React 中我們有時候容易寫出不是 pure render 的 function,這會造成 PureComponent shouldComponentUpdate
的結果都會是 ture,例如:
// onClick 每次產生新的 function<a href="#" onClick={() => send(user.id)}>
Click Me
</a>
// style 每次都會產生新的物件<div style={{ color: 'red' }} /> // filterItems每次都會產生新的物件render() { const filterItems = this.props.items.filter(...) return (
{
filterItems.map(() => ... } )}
這些可以透過預先將變數寫在 class 外面,或是 class 的 this,或是在 componentWillReceiveProps setSstate 避免。
四、使用 class properties 讓寫法更乾淨
class properties 是新的語法,目前還在提案的階段,但已經可以透過 Babel class-properties-transform 來使用讓我們少寫許多相同的程式碼。
好處是過往 event bind this 我們可以這樣寫:
// bad: 每次 bind 會產生新的 function<a href="#" onClick={handleClick.bind(this)}>
Click me
</a>
也可以使用下面這種寫法:
// bad: 每次都需要多寫 bind class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
} handleClick() {
// handle click
}}
但現在我們可以直接這樣寫:
// goodclass Toggle extends React.Component {
state = {isToggleOn: true};
handleClick = () => {
// handle click
}
}
而 Prop type 的檢查也可以直接寫法在裡面
class Toggle extends React.Component {
.... static propTypes = {
title: string
}
static defaultProps = {
title: 'Name'
}...
}
五、Function vs const
我們可以直接透過 Function 定義 component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
而在 ES6 的寫法下,也可以使用 arrow function 簡化:
const Welcome = (props) => ((
<h1>Hello, {props.name}</h1>;
))
然而,雖然寫法上更為簡潔,但因為是匿名函數,會造成在 debug 的時候,Function 的名稱會難以辨識: <anonymous>。
六、Render Props & Hight Order Component 技巧
當我們需要更加地 Reuse Component,並讓所有 Component 擁有最少的相同的程式碼,可以透過 Render Props 或是 HOC 的技巧,簡化 component
Render Props:
The term “render prop” refers to a simple technique for sharing code between React components using a prop whose value is a function.
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
Hight Order Component
Concretely, a higher-order component is a function that takes a component and returns a new component.
結論
雖然標題是「最佳實踐」,但我相信最後這些寫法都是一種權衡,有時候是為了讓我們可以寫的更快,有時候是為了效能,而有時候是為了可讀性,而這些或許或根據不同的專案,不同情況而決定,但最重要的或許是先了解它們的優缺點,才能知道怎麼運用。