下面从三个维度去总结hook的学习
useState
为什么使用useState
在function组件中维护state的时候需要用
怎么使用useState
const [name, setName] = useState('George')
useState知识点
重点:useState的初始值只有在第一次有效
例子:当点击update name的时候,虽然Child组件是收到了,但是并没有通过useState赋值给name
const Child = React.memo(({ data }) => {
const [name, setName] = React.useState(data);
return (
<Box>
{name} --123123- {data}
</Box>
);
});
const Hook =()=>{
const [name, setName] = React.useState('rose');
return (
<Box>
<Button onPress={() => setName('jack')}>
<Text>update count </Text>update name
</Button>
<Child data={name} />
</Box>
);
}
useEffect
为什么使用useEffect
在函数组件中使用class的生命周期,可以看做是componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
怎么使用useEffect
useEffect(()=>{
...
})
useEffect知识点
姿势一:只在第一次使用使用,例如用来请求异步数据
useEffect最后,加了[]就表示只第一次执行
useEffect(()=>{
const users = 获取用户信息()
},[])
姿势二:用来替代willUpdate等每次渲染都会执行的生命函数
useEffect最后,不加[]就表示每一次渲染都执行
useEffect(()=>{
const users = 获取用户信息()
})
姿势三:每次渲染都执行会影响性能,所以
useEffect最后,加[],并且[]里面加的字段就表示,这个字段有更改effect才执行
useEffect(() => {
const users = (name改变了我才获取获取用户信息())
},[name])
姿势四:如果我们之前订阅了什么,最后在willUnMount这个生命周期里面要取消订阅,可以在useEffect这样实现:
在effect的return里面可以做取消订阅的事
useEffect(() => {
const subscription = 订阅新闻推送!
return () => {
取消订阅新闻推送!
}
},[])
为什么要取消订阅?
大家都知道,render了之后会执行重新useEffect,如果useEffect里面有一个每setInterval...那么每次render了,再次执行useEffect就会再创建一个setInterval,然后就混乱了...可以把下面案例return的内容删掉感受下
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log('use effect...', count);
const timer = setInterval(() => setCount(count + 1), 1000);
return () => clearInterval(timer);
});
useMemo
为什么使用useMemo
举个栗子
const Child = React.memo(({ data }) => {
console.log('child render...', data.name);
return (
<Box>
<Box>child</Box>
<Box>{data.name}</Box>
</Box>
);
});
export const Hook = () => {
console.log('Hook render...');
const [count, setCount] = React.useState(0);
const [name, setName] = React.useState('rose');
const data = {
name,
};
return (
<Box>
<Text>{count}</Text>
<Button onPress={() => setCount(count + 1)}>update count </Button>
<Child data={data} />
</Box>
);
};
当点击按钮更新的时候,effect组件就会render,一旦render之后,刷新到data,这一行代码就会生成新的内存地址对象,那么就算带着memo的child组件,也会跟着重新render。
这样多余的render,就会造成性能浪费!于是useMemo就派上用场了
怎么使用useMemo
const data = useMemo(()=>{
return {
name
}
},[name])
因为使用了useMemo,它具有一个暂存的能力,暂存了上一次的name结果。在data重新刷新的时候,如果发现name值对比上一次的name并没有改变,那么这次data就不重新赋值成新的对象了。
没有新的对象,就没有新的内存地址,那么Child就不会重新render。
useMemo知识点
姿势一:首先,memo的用法是:函数组件里面的PureConponent
但是,如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
姿势二:memo是浅比较,意思是,对象之比较内存地址,只要内存地址没有改变,对象里面的值怎么改变都不会触发render
useCallback
useMemo解决了值的缓存问题,那么函数就是使用useCallback
为什么使用useCallback
举个栗子
const Child = React.memo(({ data, onChange }) => {
console.log('child render...');
return (
<Box>
<Text>child</Text>
<Box>{data}</Box>
<TextInput onChange={onChange} />
</Box>
);
});
export const Hook = () => {
console.log('Hook render...');
const [count, setCount] = React.useState(0);
const [name, setName] = React.useState('rose');
const [text, setText] = React.useState('');
const onChange = React.useCallback(e => {
setText(e.target.value);
}, []);
return (
<Box>
<Text>{count}</Text>
<Text>{text}</Text>
<Button onPress={() => setCount(count + 1)}>update count </Button>
<Child data={name} onChange={onChange} />
</Box>
);
};
尽管值并没有变化,但是还是重新渲染child,造成了性能浪费
怎么使用useCallback
const onChange = useCallback((e)=>{
setText(e.target.value)
},[])
useCallback知识点
姿势一:useMemo是缓存值的,useCallback是缓存函数的
姿势二:没有依赖,添加空的依赖,就是空数组!
useContext
为什么使用useContext
等同class里面的context。
怎么使用useContext
import React from 'react';
export interface IGlobalLoadingContextValue {
visible: boolean;
setVisible: React.Dispatch<React.SetStateAction<boolean>>;
}
export const GlobalLoadingContext =
React.createContext<IGlobalLoadingContextValue>({
visible: false,
setVisible: () => {},
});
export const GlobalLoadingProvider: React.FC = (props: any) => {
const [visible, setVisible] = React.useState<boolean>(false);
return (
<GlobalLoadingContext.Provider
value={{
visible,
setVisible,
}}>
{props.children}
</GlobalLoadingContext.Provider>
);
};
自定义hook
自定义一个当resize 的时候 监听window的width和height的hook
import {useEffect, useState} from "react";
export const useWindowSize = () => {
const [width, setWidth] = useState()
const [height, setHeight] = useState()
useEffect(() => {
const {clientWidth, clientHeight} = document.documentElement
setWidth(clientWidth)
setHeight(clientHeight)
}, [])
useEffect(() => {
const handleWindowSize = () =>{
const {clientWidth, clientHeight} = document.documentElement
setWidth(clientWidth)
setHeight(clientHeight)
};
window.addEventListener('resize', handleWindowSize, false)
return () => {
window.removeEventListener('resize',handleWindowSize, false)
}
})
return [width, height]
}
怎么使用
const [width, height] = useWindowSize()