有無 state
- 如果有 state
- 用 component 的方式宣告一個 class
- 可以 access state
- 透過 this.state 或 this.props
- 有生命週期 hook
class XY extend Component{
...
}
- 如果沒有 state
- 用 function 的方式就好了
const XY = (props) => {
...
}
Container 與 Presentational Components
- Presentational Components
- 用途:怎麼看事情(Markup、外觀)
- 是否讓 Redux 意識到:否
- 取得資料方式:從 props 取得
- 改變資料方式:從 props 去呼叫 callback function
- 寫入方式:手動處理
- Container Components
- 用途:怎麼做事情(擷取資料,更新 State)
- 是否讓 Redux 意識到:是
- 取得資料方式:訂閱 Redux State(store)
- 改變資料方式:Dispatch Redux Action
- 寫入方式:從 React Redux 產生
Component 主要負責單純的 UI 的渲染,而 Container 則負責和 Redux 的 store 溝通,作為 Redux 和 Component 之間的橋樑
Container 與 Presentational Components 入門
key
- 每個元素都有一個唯一的 key,可以來比較哪一個元素需要被更新(它的 DOM)
- 不建議用 index
- 如果列表改變,每一個元素都會收到一個新的 index
- 通常都用 id
- 不建議用 index
不要直接改變陣列和物件(因為這些都是指標)
- 複製物件
- 利用 Object.assign() 複製
const person = Object.assign({}, this.state.person);
- 利用 … 複製
const person = { ...this.state.person };
- 利用 Object.assign() 複製
-
複製陣列
- 利用 splice() 複製
const persons = this.state.persons.splice();
- 利用 … 複製
const persons = [...this.state.persons];
- 淺層複製的問題
JSX
- jsx 要有判斷式的話,裡面只能用三元表示式
// 只能用
{
showPerson ? <p>I'm a person.</p> : null;
}
// 不能用
{
if (showPerson) {
return <p>I'm a person.</p>;
} else {
return null;
}
}
生命週期
Mounting 載入
元件正要被載入到 DOM 階段
-
componentWillMount()
- 這個方法是在我們元件第一次要 render 到畫面前會執行,整個生命過程只會執行一次
- 你可能會想說可以在這個地方用 setState 方法將 state 初始化,雖然 setState 方法的確可以在這邊被調用,不過沒人會這樣寫,應該要寫在 constructor 裡面,用 this.state 來對 state 初始化
-
componentDidMount()
- 大部分 Ajax 要進行處理都是在這個方法裡面調用,不在 componentWillMount() 階段進行 Ajax 主要是因為沒辦法確定對資料的請求能在畫面 render 之前處理好
Updating 更新
當 state 或 props 改變時,會進行 re-render 階段
-
componentWillReceiveProps(nextProps)
- 當收到新的 props,會觸發此函數
- 如果需要收到新的 props ,需要改變 state 時,可以調用此函數
- 在剛開始 init props 階段,並不會觸發此函數
- this.setState() 也不會觸發此函數
-
shouldComponentUpdate(nextProps, nextState)
- 在此函數內判斷是否新的值和舊的值不一樣,再決定要不要 re-render
- 這麼做有個好處就是一旦你有一大堆組件的情況,每次在面對傳入一樣的 props 或 state 都還要 re-render 那就太浪費效能了,所以這個方法能幫你解決這些問題,讓效能變好
- return true 代表照正常 re-render 方式變更元件
- return false 代表就不會變更元件
- 不要做太多深層的檢查或使用 JSON.stringify(),以避免造成效能上的問題
- PureComponet 已經內建這種檢查,他會檢查所有新舊 state 和 props,如有差異才會繼續更新
// 改變 props
shouldComponentUpdate (nextProps, nextState){
return nextProps.person != this.state.persons;
// 改變 state
shouldComponentUpdate (nextProps, nextState){
return nextState.person != this.state.persons;
}
-
componentWillUpdate()
- 不能在這裡呼叫 this.setState(),會陷入無限迴圈
- 不能在這裡進行 dispatch Redux action,這樣會導致在 componentWillUpdate 之前觸發另一個更新元件的動作
-
componentDidUpdate()
- 此函數在初始執行階段不會被觸發
- 當 shouldComponentUpdate() 返回 false 時,也不會被觸發
-
getSnapshotBeforeUpdate(react16.3)
- 可以用來記錄滾動位置
Unmounting 移除
元件要從 DOM 移除階段
- componentWillUnmount()
- 在元件被刪除”之前”,會立刻執行此函數
- 可以被用來解除一些時間綁定、中斷 HTTP 請求或者進行 unsubscribe 處理
正確的使用 setState
- 陣列和物件需要先複製一份,再改變,再更新
- 如果需要取得之前的值
this.setState({
count: this.count + 1
});
- 應該改為,避免同時也有其他人再改一樣的值
this.setState((prevState, props) => {
return {
count: prevState.count + 1
};
});
其他
- radium
- 在 js 樣式新增 :hover
- css modules 自動升成唯一的 css 類名
-
HOC (High-Order Components) 高級元件 (react16)
-
aux
- 不想要有一個空的 div 當根
return ( <div> <h1>title</h1> <p>i'm a pig.</p> <p>i'm 12 yeas old.</p> </div> );
- 改用 aux
const aux = props => props.children; export default aux;
import Aux from "./hoc/aux"; return ( <Aux> <h1>title</h1> <p>i'm a pig.</p> <p>i'm 12 yeas old.</p> </Aux> );
-
-
- 用來確認 props 傳入的型態
import PropTypes from 'prop-types'; class Person extend Component { ... } Person.propTypes = { click: PropTypes.func, name: PropTypes.string, age: PropTypes.number }
- 設定預設值
import PropTypes from "prop-types"; class Greeting extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } Greeting.defaultProps = { name: "Stranger" }; ReactDOM.render(<Greeting />, document.getElementById("example"));
- ref
- 用來讓 input focus 之類的?
- context (react16.3)