自己也在学习中,百度到的文章都是翻译API的,记录一下自己的理解吧,本身是小白,有错误请指出。
目前在学习当中,发现React的偏向于将逻辑从组件中抽出,使组件仅仅用于接收数据渲染,而逻辑全放入Hook中操作。
用于返回组件的初始化state并且返回更新方法,它只关心你传入的初始值,可以包装一下更便于抽出逻辑,组件只用于渲染。useState返回的第一个参数就是你initialState传入的值,也只是这个值,其他的不会影响这个值(如下面代码的注释);第二个参数是更新该值的方法,可以看到preCount返回的也只是一个count值。
//包装一下
function useMyState(initialState=1){
const [_state, _setState] = useState(initialState);
return [_state,(fn)=>{
console.log('操纵state',_state)
return _setState((prevState)=>fn(prevState))
}]
}
export default function Login(props) {
const [count, setCount] = useMyState();
const [miss, setMiss] = useMyState(3);//这个不会影响count
return <div>
登录{count}
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</div>
}
但是useState()直接传值这种形式,每次界面渲染都会重新创建这个初始状态,所以我们需要传入个匿名函数即可。
const [_state, _setState] = useState(()=>initialState);
替代componentDidMount、componentDidUpdate和componentWillUnmount,使相应的绑定函数变得更加轻松。要想只在mount上运行并在unmount上清理,update上不做绑定,则第二参数传入空数组;第二参数传入值则react内部会判断之前值和传入值的变化去重新监听。(注意其实document的监听是无法取消监听的,应该监听其他dom)
function useMyEffect(count){
useEffect(() => {
document.title = `You clicked ${count} times`;
console.log(11111111,'监听')
document.addEventListener('mousedown', (e) => {//注意其实document的监听是无法取消监听的,应该监听其他dom
console.log('mousedown 操作 ',count)
})
return () => {
console.log(22222222,'取消监听')
document.removeEventListener('mousedown',()=>{////注意其实document的监听是无法取消监听的,应该监听其他dom
console.log('mousedown remove')
})
};
},[]);
}
//组件中引用并添加
useMyEffect(count)//
显示当前context的值,且context改变时,该值也会更新
function useMyContext(defaultValue){
return React.createContext(defaultValue);
}
const MyContext = useMyContext({theme:'default'});
console.log(useContext(MyContext)) //打印: {theme: "default"}
一般我们这样去使用它:
const TodoSome = React.createContext(null);
function doOther(){
//===
}
return (
<TodoSome.Provider value={doOther}>
<DeepTree todos={todos} />
</TodoSome.Provider>
);
//DeepTree
const doOther = useContext(TodoSome);
useCallback(fn, inputs)相当于useMemo(() => fn, inputs)。二者有点相似有放在一起说了,都是返回一个渲染dom;useCallback返回的是一个函数,useMemo直接就是dom。第二个数组参数用来判断是否重新渲染,相当于之前的shouldComponentUpdate操作,这个判断是用“Object.is”来判断的,用+0和-0测试也会执行刷新。
function useMyCallback({a,b}) {
return useCallback(() => {
console.log('useCallback')
return <div>{a+b}</div>
},[a, b])
}
function useMyMeno({a,b}){
return useMemo(()=>{
console.log('useMyMeno')
return <div>{a+b}</div>
},[a, b])
}
//组件中
let [ab,setAb] = useState({a:-0,b:+0})
let cbDom = useMyCallback(ab);
console.log(cbDom)//ƒ () {console.log('useCallback'); return _react2.default.createElement('div', null,a + b);}
cbDom = cbDom()//{$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
let mmDom = useMyMeno(ab)
console.log(mmDom)//{$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}
return <div>{cbDom}注册{mmDom}
<button onClick={()=>{
setAb(preAb=>{return {a:-0,b:+0}})
}
}>doAb</button>
</div>
别被他的名字所欺骗,以为只是配合ref使用的,他是一个该函数组件的实例变量(内部方法共享的变量),类似于之前Class组件的this.xx,不仅可以作为ref的实例,还可以是任何变量的实例。
//class写法
constructor(){
tihs.interval;
}
componentDidMount(){
tihs.interval = setInterval(() => {
// ...
});
}
componentWillUnmount(){
clearInterval(tihs.interval);
}
//函数组件写法
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id;
return () => {
clearInterval(intervalRef.current);
};
});
// ...
}
这样去创建useRef,每次渲染时也都会重新创建,如果你想避免这种情况,请使用下面这种形式。
const ref = useRef(new IntersectionObserver(onIntersect));