react-hooks HOOKS
- hooks概念在React Conf 2018被提出來,并將在未來的版本中被引入,hooks遵循函數式編程的理念,主旨是在函數組件中引入類組件中的狀態和生命周期,并且這些狀態和生命周期函數也可以被抽離,實現復用的同時,減少函數組件的復雜性和易用性。
- 函數組件 (functional component) 內部能夠”鉤住“ React 內部的 state 和 life-cycles。
- 真正功能強大的地方是使我們能夠更輕松地復用組件邏輯(custom hooks)
- 讓FunctionalComponent具有ClassComponent的功能
設計Hooks主要是解決ClassComponent的幾個問題:
- 很難復用邏輯(只能用HOC,或者render props),會導致組件樹層級很深
- 會產生巨大的組件(指很多代碼必須寫在類里面)
- 類組件很難理解,比如方法需要bind,this指向不明確
npm install react@16.7.0-alpha.2
npm install react-dom@16.7.0-alpha.2
npm install eslint-plugin-react-hooks@next
// Your ESLint configuration
{
"plugins": [
// ...
"react-hooks"
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error"
}
}
Hooks API Reference
** Basic Hooks **
useState
useEffect
useContext
** Additional Hooks **
useReducer
useCallback
useMemo
useRef
useImperativeMethods
useMutationEffect
useLayoutEffect
Rules of Hooks
- 只能在頂層調用Hooks 。不要在循環,條件或嵌套函數中調用Hook
- 只能在functional component中使用
State Hook
定義組件狀態
- 避免組件的 state 結構過于臃腫,能夠獨立處理每個 state
- 寫法非常直觀,一眼就可以看出和這個 state 相關的兩個變量
const useStateExample = () => {
const [count, setCount] = useState(0);
const [list, setList] = useState([]);
const [object, setObject] = useState({ name: 'lishishi', age: 28 });
}
State Hooks的定義必須在函數組件的最高一級,不能在嵌套,循環等語句中使用
一個函數組件可以存在多個State Hooks,并且useState返回的是一個數組,數組的每一個元素是沒有標識信息的,完全依靠調用useState的順序來確定哪個狀態對應于哪個變量,所以必須保證使用useState在函數組件的最外層
最主要的原因就是你不能確保這些條件語句每次執行的次數是一樣的,也就是說如果第一次我們創建了state1 => hook1, state2 => hook2, state3 => hook3這樣的對應關系之后,下一次執行因為something條件沒達成,導致useState(1)沒有執行,那么運行useState(2)的時候,拿到的hook對象是state1的,那么整個邏輯就亂套了,所以這個條件是必須要遵守的!
const useStateExample = () => {
if(Math.random() > 1) {
const [count, setCount] = useState(0);
const [list, setList] = useState([]);
}else {
const [object, setObject] = useState({ name: 'lishishi', age: 28 });
}
}
Effect Hook
實現生命周期 (life-cycles)
- 類似 redux 中的 subscribe,每當 React 因為 state 或是 props 而重新 render 的之后,就會觸發 useEffect 里的這個 callback listener(在第一次 render 和每次 update 后觸發)
- 在生命周期內做的操作很多都會產生一些 side-effect(副作用)的操作,比如更新 DOM,fetch 數據,等等。
useEffect(() => {
//componentDidMount和componentDidUpdate周期的函數體
return ()=>{
//componentWillUnmount周期的函數體
}
})
// ---------------------
useEffect(() => {
//僅在componentDidMount的時候執行
},[]);
// -----------------------
useEffect(() => {
//僅在componentDidMount的時候執行
//只有stateName\props.id的值發生改變
},[stateName,props.id]);
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
}
if (prevProps.id !== this.props.id) {
}
}
- useEffect函數必須位于函數組件的最高一級
useState('Mary')
useEffect(persistForm)
useState('Poppins')
useEffect(updateTitle)
Context Hook
替代了 <Context.Consumer> 使用 render props 的寫法,使組件樹更加簡潔。
Reducer Hook
相當于組件自帶的 redux reducer,負責接收 dispatch 分發的 action 并更新 state
配合hooks重新實現react-redux
useReducer + useContext 鉤子上進行一層很簡單的封裝以達到和以往 react-redux \ redux-thunk \ redux-logger 類似的功能
npm install react-hooks-redux
React.memo() React 16.6.0
- PureComponent 要依靠 class 才能使用。而 React.memo() 可以和 functional component 一起使用
const MySnowyComponent = React.memo(function MyComponent(props) {
// only renders if props have changed!
});
// can also be an es6 arrow function
const OtherSnowy = React.memo(props => {
return <div>my memoized component</div>;
});
// and even shorter with implicit return
const ImplicitSnowy = React.memo(props => (
<div>implicit memoized component</div>
));
useRef
useCallBack
- e.g. shouldComponentUpdate ; This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
useMemo
- useMemo will only recompute the memoized value when one of the inputs has changed
- useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs)
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useImperativeMethods
- useImperativeMethods customizes the instance value that is exposed to parent components when using ref
- useImperativeMethods(ref, createInstance, [inputs])
useMutationEffect useLayoutEffect useEffect 差別
useMutationEffect
It fires synchronously before Layout phase i.e. during the same phase that React performs its DOM mutations. Use it to perform blocking custom DOM mutations without taking any DOM measurement/reading layout.useLayoutEffect
It fires synchronously after all DOM mutations but before Paint phase. Use this to read layout(styles or layout information) from the DOM and then perform blocking custom DOM mutations based on layout.useEffect
It runs after the render is committed to the screen i.e. after Layout and Paint phase. Use this whenever possible to avoid blocking visual updates
注意
- 目前react-hot-loader不能和hooks一起使用