react函数组件不想类组件那样有生命周期函数,以及state。但是我们可以通过hook来优化我们的性能。
一个组件重新重新渲染,一般三种情况:
function Test() {
const [value,setValue] = useState(0)
return ( <div>
{value}
<button onClick={()=>{setValue(1)}}>changeValue</button>
<Testson name='lisi' />
</div>
)
}
function Testson(props) {
console.log('Testson 重新渲染了')
return (
<p>{props.name}</p>
)
}
在上面的代码执行的时候,Testson的props的值没有改变,只有父组件的value的值改变了。重新渲染了父组件,也重新渲染了子组件。
通过react.memo包裹子组件,在props不变的情况下,Testson是不会二次渲染的。修改后的代码如下
const Testson = React.memo(function(props) {
console.log('Testson 重新渲染了')
return (
<p>{props.name}</p>
)
})
react.memo高级用法
const Testson = React.memo(function(props) {
console.log('Testson 重新渲染了')
return (
<p>{props.name}</p>
)
},(preProps,nextProps) => {
//判断逻辑
return true //false、true ===》false渲染、true不渲染
})
用法和类组件的shouldComponentUpdate()差不多;
我们再添加一个需求,就是通过Testson子组件修改父组件的myKey。代码如下。
function Test() {
const [value,setValue] = useState(0)
const [myKey,setMyKey] = useState('mykey')
return ( <div>
{myKey}---{value}
<button onClick={()=>{setValue(1)}}>changeValue</button>
<Testson name='lisi' click={() => {setMyKey('myKey has changed')}}/>
</div>
)
}
const Testson = React.memo(function(props) {
console.log('Testson 重新渲染了')
return (
<div>
<button onClick={props.click}>changeMyKey</button>
<p>{props.name}</p>
</div>
)
再以上的代码执行中,点击changeValue按钮还是会重新渲染子组件,虽然props并没有改变,这是一个不必要的渲染。为什么会重新渲染来呢?这是因为父组件重新渲染了,所以props的值改变了,这个值是props.click,因为这是一个函数,每次渲染都会重新创建,所以它的指向也就不同了。就像创建了两个对象一样。我们通过usecCallback来处理;
function Test() {
const [value,setValue] = useState(0)
const [myKey,setMyKey] = useState('mykey')
const changeMykey = useCallback(() => {setMyKey('myKey has changed')},[])
return ( <div>
{myKey}---{value}
<button onClick={()=>{setValue(1)}}>changeValue</button>
<Testson name='lisi' click={changeMykey}/>
</div>
)
}
const Testson = React.memo(function(props) {
console.log('Testson 重新渲染了')
return (
<div>
<button onClick={props.click}>changeMyKey</button>
<p>{props.name}</p>
</div>
)
})
通过以上代码就能解决了子组件不必要的渲染。
在调用 useEffect 后,相当于告诉 React 在每一次组件更新完成渲染后,都调用传入 useEffect 中的函数,包括初次渲染以及后续的每一次更新渲染。
useMemo可以缓存计算。学过vue的同学都知道vue有computed可以缓存计算的值。react和computed差不多。设计出来都是为了缓存计算;
function App() {
const [num, setNum] = useState(0);
function expensiveFn() {
let result = 0;
for (let i = 0; i < 10000; i++) {
result += i;
}
console.log(result)
return result;
}
const base = useMemo(expensiveFn, []);
return (
<div className="App">
<h1>count:{num}</h1>
<button onClick={() => setNum(num + base)}>+1</button>
</div>
);
}
以上代码执行。不管点多少次+1都只会输出一次result,也就是expensiveFn值计算一次。通过useMemo缓存了expensiveFn的计算结果。