我们都知道,当父组件的状态值(state)和属性值(props)发生改变后,子组件会随之重新渲染。
但是实际开发过程中,某些场景我们并不想让子组件重新渲染,以提高性能。一起看下面的例子:

  1. import React, { useState, memo } from 'react';
  2. import { Button, Card, Alert } from 'antd';
  3. // 子组件
  4. const Child = () => {
  5. console.log("渲染了子组件");
  6. return (
  7. <Alert message='我是一个简单的子组件' />
  8. );
  9. }
  10. // 父组件
  11. const Parent = () => {
  12. const [count, setCount] = useState(0);
  13. // 按钮点击事件
  14. const handleClick = () => {
  15. setCount(count + 1);
  16. }
  17. return (
  18. <Card>
  19. <p>{count}</p>
  20. <p><Button onClick={handleClick}>点击+1</Button></p>
  21. <Child />
  22. </Card>
  23. );
  24. }
  25. export default Parent;

image.png

我们的目的,仅仅是点击+1时,让数字增加1,即父组件渲染。但是很显然,每次父组件重新渲染后,子组件也随之渲染了。既然子组件没有任何改动,为什么还让它渲染呢?

出于优化考虑:
我们期待的结果是当子组件的state和props没有发生改变时,即使父组件重新渲染,也不要渲染子组件。

解决办法是,在子组件的最外层用React.memo,修改如下:

  1. import React, { useState, memo } from 'react';
  2. import { Button, Card, Alert } from 'antd';
  3. // 子组件:用React.memo包裹
  4. const Child = memo(() => {
  5. console.log("渲染了子组件");
  6. return (
  7. <Alert message='我是一个简单的子组件' />
  8. );
  9. })
  10. // 父组件
  11. const Parent = () => {
  12. const [count, setCount] = useState(0);
  13. // 按钮点击事件
  14. const handleClick = () => {
  15. setCount(count + 1);
  16. }
  17. return (
  18. <Card>
  19. <p>{count}</p>
  20. <p><Button onClick={handleClick}>点击+1</Button></p>
  21. <Child />
  22. </Card>
  23. );
  24. }
  25. export default Parent;

image.png
当我们再次点击+1时,控制台并没有打印出:”渲染了子组件”,表明子组件并没有渲染。

思考:

  1. import React, { useState, memo } from 'react';
  2. import { Button, Card, Alert } from 'antd';
  3. // 子组件
  4. const Child = memo(({ textInfo }) => {
  5. console.log("渲染了子组件");
  6. return (
  7. <Alert message='我是一个简单的子组件' />
  8. );
  9. })
  10. // 父组件
  11. const Parent = () => {
  12. const [count, setCount] = useState(0);
  13. const [text, setText] = useState("你好,世界!");
  14. // 按钮点击事件
  15. const handleClick = () => {
  16. setCount(count + 1);
  17. }
  18. return (
  19. <Card>
  20. <p>{count}</p>
  21. <p><Button onClick={handleClick}>点击+1</Button></p>
  22. <Child textInfo={{ text }} />
  23. </Card>
  24. );
  25. }
  26. export default Parent;

我们增加一个变量 text ,当我们点击+1,发现子组件在控制台还是打印出:”渲染了子组件”。有的小伙伴可能该问了,text 的值一直是:”你好,世界!”,props并没有发生改变,子组件为啥还是会重新渲染呢?难道是React.memo失效了?

如果我把

  1. <Child textInfo={{ text }} />

更改为:

  1. <Child textInfo={ text } />

结果是不是会一样呢?

如果不懂怎么解决上述问题,嘿嘿。那就老实和我一起继续往下学习吧:React Hook — useMemo