hook总览
https://github.com/puxiao/react-hook-tutorial/blob/master/04%20useEffect%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95.md

关于useEffect https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/
关于useContext的优化 http://www.ptbird.cn/react-createContex-useContext.html

React.forwardRef

React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中(作为回调的第二个参数。这种技术并不常见,但在以下两种场景中特别有用:

  1. const FancyButton = React.forwardRef((props, ref) => (
  2. <button ref={ref} className="FancyButton">
  3. {props.children}
  4. </button>
  5. ));
  6. // You can now get a ref directly to the DOM button:
  7. const ref = React.createRef();
  8. <FancyButton ref={ref}>Click me!</FancyButton>;

ps:
Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。
//是指把组件真实dom的引用传递到外部。这个引用通过React.createRef();创建
https://zh-hans.reactjs.org/docs/forwarding-refs.html

useState

一个闭包+异步问题
a是一个基础类型,如果useEffect不传第二个参数且组件没有重新渲染,a永远是初始值1
此时应该用setState(a1=>a1+1),a1是setState内部维护的最新值。

  1. import React, { useState,useEffect} from 'react';
  2. function Component() {
  3. const [a, setA] = useState(0);//定义变量a,并且默认值为0
  4. //定义第1个useEffect,专门用来处理自动累加器
  5. useEffect(() => {
  6. let timer = setInterval(() => {setA(a+1)},1000);// <-- 请注意这行代码,暗藏玄机
  7. return () => {
  8. clearInterval(timer);
  9. }
  10. }, []);//此处第2个参数为[],告知React以后该组件任何更新引发的重新渲染都与此useEffect无关
  11. //定义第2个useEffect,专门用来处理网页标题更新
  12. useEffect(() => {
  13. document.title = `${a} - ${Math.floor(Math.random()*100)}`;
  14. },[a])
  15. return <div> {a} </div>
  16. }
  17. export default Component;

useEffect

指定useEffect第二个参数,明确监听的值,减少性能损耗。(不带参数默认是监听所有update

  1. import React, { useState,useEffect} from 'react';
  2. function Component() {
  3. const [obj,setObj] = useState({a:0,b:0});
  4. useEffect(() => {
  5. document.title = `${obj.a} - ${Math.floor(Math.random()*50)}`;
  6. }); //注意此时我们并未设置useEffect函数的第2个参数
  7. return <div>
  8. {JSON.stringify(obj)}
  9. <button onClick={() => {setObj({...obj,a:obj.a+1})}}>a+1</button>
  10. <button onClick={() => {setObj({...obj,b:obj.b+1})}}>a+1</button>
  11. </div>
  12. }
  13. export default Component;

usememo

useCallback

由于function是引用类型,每次渲染反复创建新function,会导致依赖于function的子组件无法优化的阻止更新
usecallback
useCallback( callback: T, deps: Array | void | null)
当方法依赖的deps改变时才新建方法

  1. import React from 'react'
  2. function Button({label,clickHandler}) {
  3. //为了方便我们查看该子组件是否被重新渲染,这里增加一行console.log代码
  4. console.log(`rendering ... ${label}`);
  5. return <button onClick={clickHandler}>{label}</button>;
  6. }
  7. export default React.memo(Button); //只能对props进行浅比较
  8. ----------------------
  9. function Mybutton() {
  10. const [age,setAge] = useState(34);
  11. const [salary,setSalary] = useState(7000);
  12. useEffect(() => {
  13. document.title = `Hooks - ${Math.floor(Math.random()*100)}`;
  14. });
  15. //按钮执行一次之后,该组件重新渲染,然后function是重新生成的,指向不同的引用
  16. //绑定作为子组件的props时会看作不同的值,导致绑定方法的子组件都重新渲染
  17. const clickHandler01 = () => {
  18. setAge(age+1);
  19. };
  20. const clickHandler02 = () => {
  21. setSalary(salary+1);
  22. };
  23. //useCallback会在react内维护上一次创建的方法的内存,如果重新赋值
  24. const clickHandler01 = useCallback(() => {
  25. setAge(age+1);
  26. },[age]);
  27. return (
  28. <div>
  29. {age} - {salary}
  30. <Button label='Bt01' clickHandler={clickHandler01}></Button>
  31. <Button label='Bt02' clickHandler={clickHandler02}></Button>
  32. </div>
  33. )
  34. }