当村口的狗叫了,其它的狗也跟着叫了,但它们不知道为什么叫.
react hook是什么
react hook是什么?引入官网的话,react hook是react16.8新增的新特性,它可以让你在不编写class的情况下,使用state以及其他react特性。
为什么要使用react hook
在react组件有class组件和function组件之分,也可以分状态组件和无状态组件,function组件的性能要比class组件的性能要高。
这里主要说为什么要使用hook
这里主要说为什么要使用hook
- this指向问题
- 状态逻辑复用
- 关注点分离
react hook的使用
StateHook
StateHook提供了在函数组件中使用state的能力
import React,{useState} from 'react';
function Count() {
const [count,setCount] = useState(0);
const [num,setNum] = useState(10);
return (
<div>
<div>
<button onClick={()=>setCount(count+1)}>{count}</button>
</div>
<div>
<button onClick={()=>setCount(num+2)}>{num}</button>
</div>
</div>
)
}
这是一个简单的例子,使用useState返回一个数组,包含两项,第一项是值可以理解为使用class组件时定义在state里面的属性,第二项是改变值的函数,可以理解为setState的一个二层封装。
注意点:
注意点:
- 严格按照useState调用的顺序,不能动态改变useState的调用数量和顺序
- useState接收一个参数作为默认值或者接收函数,都以第一次渲染中调用useState为准,如果是函数,则只会调用一次,返回的值作为默认值
你可能会产生几个问题?
- 1.stateHook怎么知道是返回这个组件的count,而不是返回其他组件count
- 2.stateHook怎么知道返回的是count的值还是num的值
useState只会返回该组件的count,个人猜测是按照执行上下文来做判断.
stateHook怎么知道返回的是count的值还是num的值,这里是按照调用顺序来区分,第一次调用返回count的值 第二次返回num值。
stateHook怎么知道返回的是count的值还是num的值,这里是按照调用顺序来区分,第一次调用返回count的值 第二次返回num值。
EffectHook
函数组件是不支持生命周期函数的,因此EffectHook就提供了这样一个功能。
先说明一下
useEffect接收一个函数和一个数组作为参数,只有在数组中的每一项不改变的情况下才不会重新调用该函数。
因此有以下几种情况:
因此有以下几种情况:
-
1.只传递第一个参数,那么这个函数在每次页面渲染之后都会调用,类似componentDidMount和componentDidUpdate
function App(props) { const [count,setCount] = useState(0); useEffect(()=>{ //每次渲染后都会调用 console.log('mount and update'); }); ... }
- 2.接收两个参数,第一个参数传递的是函数,另一个参数传递的是空数组,那么这个函数只会在页面组件渲染到页面上调用,只会调用一次 类似componentDidMount
function App(props) { const [count,setCount] = useState(0); useEffect(()=>{ //类似componentDidMount 只会调用一次 console.log('mount and update'); },[]); ... }
-
3.在2的情况下,回调返回一个函数,那么这个函数可以看成是componentWillUnmount,不过有点不一样的是,该函数的调用情况有两种,第一种是组件卸载。第二种是下一次组件开始渲染之前调用
function App(props) { const [count,setCount] = useState(0); useEffect(()=>{ return ()=>{ console.log('mount and update'); }; }); ... }
-
4.第二个参数不是空数组,则只有数组里面的每一项不改变对的时候,才不会触发
function App(props) { const [count,setCount] = useState(0); useEffect(()=>{ console.log('mount and update'); },[count===4]); ... }
ContextHook
ContextHook提供函数组件使用context的能力
const CountText = createContext(1);
function App(props) {
const [count,setCount] = useState(0);
return (
...
<Counttext.Provider value={{count}}>
<Tab/>
</Counttext.Provider>
...
)
}
function Tab(props) {
const context = useContext(CountText);
return (
<div>
{context.count}
</div>
);
}
MemoHook&&CallbackHook
MemoHook和CallbackHook都是性能优化的手段,类似class组件的shouldComponentUpdate。
function App() {
const [count,setCount] = useState(0);
const double = useMemo(()=>{
return count * 2;
},[count===4]);
return (
<div>
{double}
</div>
);
}
</pre>
</code>
第二个参数和useEffect的第二个参数的用法一样,和组件一块使用记得使用memo,当useMemo返回函数,则可以使用CallbackHook,可以把CallHook使用MemoHook的一种变种
RefHook
RefHook提供了函数组件操作DOM节点的能力.一般有两种场景会用到RefHook,分别是操作DOM节点或着组件、跨周期共享数据。
-
1.操作DOM节点
function App(props) {
const [count,setCount] = useState(0);
const ref = useRef();
const callback = useCallback(function() {
setCount(count=>count+1);
})
useEffect(()=>{
ref.current.addEventListener('click',callback,false);
return ()=>{
ref.current.removeEventListener('click',callback,false);
};
},[]);
return ( <div>
<button ref={ref}>
</button>
</div>)
}
-
2.跨周期共享数据(例子不太好)
function App(props) {
let it = useRef();
const [count,setCount] = useState(()=>0);
useEffect(()=>{
it.current = 4;
window.setInterval(()=>{
setCount(count=>{
return count+1;
})
},1000);
},[it]);
console.log(it.current);//undefined 4 4 4 4
...
}
</pre>
</code>
<div>
所以在这个情况下,如果共享数据使用state,那么数据只要改变就会重新渲染,所以采取非state,使用RefHook,怎么理解这里RefHook能够跨周期共享数据,其实可以理解成hooks返回的值与调用顺序有关
</ul>
自定义Hook
自定义Hooks可以是状态逻辑复用,注意点就是Hooksname需要use开头,清晰明了,自定义Hooks其实和普通函数也差不多,可以返回JSX也可以返回其他类型的值
function useCount() {
const [count,setCount] = useState(()=>0);
const ref = useRef();
useEffect(()=>{
ref.current = window.setInterval(()=>{
setCount(count=>{
if(count+1===10) {
window.clearInterval(ref.current);
}
return count+1;
})
},1000);
},[]);
return (
<button ref={ref}>
{count}
</button>
);
}
function App(props) {
const ele = useCount();
return ele;
}
Hook使用规则
-
1.只在顶层使用Hook
-
2.只在函数组件或者自定义Hook里面使用Hook