ReactHooks总结

3 篇文章 0 订阅
2 篇文章 0 订阅

 

Hooks API

useState

使用方法:const [count, setCount] = useState(0); 可以传入一个参数作为这个状态的默认值。

函数组件的写法

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count})
    </div>
  );
};

class组件的写法

class App extends React.Component {
  state = {
    count: 0,
  };
  render() {
    return (
      <div
        onClick={() => {
          this.setState({ count: (this.state.count += 1) });
        }}
      >
        Click(count:{this.state.count})
      </div>
    );
  }
}

useState方法的原理

let state;
const myUseState = (initVal) => {
  state = state === undefined ? initVal : state;
  const setState = (newVal) => {
    state = newVal;
    render();
  };
  return [state, setState];
};
const render = () => {
  ReactDOM.render(<App />, document.getElementById("root"));
};

在单个组件中可以使用有多个状态值,所以state应该是一个数组,上述代码改写为:

let state = [];
let index = 0;
const myUseState = (initVal) => {
  const currentIndex = index;
  state[currentIndex] =
    state[currentIndex] === undefined ? initVal : state[currentIndex];
  const setState = (newVal) => {
    state[currentIndex] = newVal;
    render();
  };
  index += 1;
  return [state[currentIndex], setState];
};
const render = () => {
  index = 0;
  ReactDOM.render(<App />, document.getElementById("root"));
};
const App = () => {
  const [count, setCount] = myUseState(0);
  const [count2, setCount2] = myUseState(1);
  return (
    <>
      <div
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click(count:{count})
      </div>
      <div
        onClick={() => {
          setCount2(count2 * 2);
        }}
      >
        Click2(count2:{count2})
      </div>
    </>
  );
};

useState必须按照固定的顺序被调用

useState()方法里面唯一的参数就是初始state。

useState()方法返回值是一个数组,分别为当前 state 以及更新 state 的函数。

为了验证useState的调用顺序的影响,把使用方法改写为如下:

// const [count, setCount] = useState(0);
let countArr = useState(0);
let count = countArr[0];
let setCount = countArr[1];

下面代码不按照固定顺序调用state,导致结果不对:

let id = 0;
const App = (props) => {
  let count = 0;
  let setCount;
  let name = "lily";
  let setName;

  if (id % 2) {
    [count, setCount] = myUseState(0);
    [name, setName] = myUseState("mike");
  } else {
    [name, setName] = myUseState("lily");
    [count, setCount] = myUseState(0);
  }
  id += 1;

  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count},name:{name})
    </div>
  );
};

useState必须按照固定的数量被调用

let id = 0;
const App = (props) => {
  let count = 0;
  let setCount;
  let name = "lily";
  let setName;
  let age = 0;
  let setAge;

  if (id % 2) {
    [count, setCount] = myUseState(0);
    [name, setName] = myUseState("mike");
    [age, setAge] = myUseState(18);
  } else {
    [name, setName] = myUseState("lily");
    [count, setCount] = myUseState(0);
  }
  id += 1;

  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count},name:{name},age:{age})
    </div>
  );
};

上述代码用的是自己写的myUseState方法实现的,实际上用useState方法,直接报错:

useStatue的默认值支持函数赋值,来延迟初始化数据的默认值

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count})
      <Child vocation="教师" />
    </div>
  );
};

const Child = (props) => {
  const [name, setName] = useState("lily");
  const [work, setWork] = useState(() => {
    return props.vocation || "学生";
  });
  return (
    <div>
      <p>姓名:{name}</p>
      <p>职业:{work}</p>
    </div>
  );
};

useEffect

使用方法:

useEffect(() => {

// 具体操作

})

函数组件的写法

const App = () => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = count;
  });
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count})
    </div>
  );
};

class组件的写法

class App extends React.Component {
  state = {
    count: 0,
  };
  render() {
    return (
      <div
        onClick={() => {
          this.setState({ count: (this.state.count += 1) });
        }}
      >
        Click(count:{this.state.count})
      </div>
    );
  }
  componentDidMount() {
    document.title = this.state.count;
  }
  componentDidUpdate() {
    document.title = this.state.count;
  }
}

默认情况下,useEffect在第一次渲染之后和每次更新之后都会执行

useEffect第二个参数

useEffect第二个参数是一个非必要的数组。第二个参数不传,组件每一次都执行;第二个参数传空数组,组件仅会执行一次。第二个参数传非空数组,只有该数组中的值都不变化时才不会执行。

useEffect返回函数

每个 useEffect 都可以返回一个函数。这是 effect 可选的清除机制。React会在组件卸载的时候执行清除操作。

const App = () => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("useEffect");
    document.title = count;
  });
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count})
      <br />
      {count % 2 ? <Child /> : null}
    </div>
  );
};

const Child = (props) => {
  const [name, setName] = useState("lily");
  const [work, setWork] = useState(() => {
    return props.vocation || "学生";
  });
  useEffect(() => {
    return () => {
      console.log("unMount");
    };
  });
  return (
    <div>
      <p>姓名:{name}</p>
      <p>职业:{work}</p>
    </div>
  );
};

useContext

使用方法:const count = useContext(CountContext);

其中CountContext是使用createContext创建的上下文对象(const CountContext = createContext());每个context对象都会返回一个Provider组件,provider接收一个value属性,传递给消费组件。

const CountContext = createContext(0);
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count})
      <CountContext.Provider value={count}>
        <CountChild />
      </CountContext.Provider>
    </div>
  );
};

const CountChild = () => {
  const count = useContext(CountContext);
  return <div>子组件{count}</div>;
};

useMemo

使用方法:useMemo(() => {}, []),把函数和依赖项数组作为参数传入useMemo,它仅会在某个依赖项改变时才重新计算memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

const App = () => {
  const [count, setCount] = useState(0);
  let double = useMemo(() => {
    console.log("useMemo");
    return count * 2;
  });
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count}, double: {double})
    </div>
  );
};

useMemo的用法类似useEffect,第一个参数是一个函数,第二个参数是这个函数相关的逻辑变量组成的一个数组。与useEffect类似,第二个参数不传,组件每一次都执行;第二个参数传空数组,组件仅会执行一次。第二个参数传非空数组,只有该数组中的值都不变化时才不会执行。

与useEffect不同的是,执行时机不同。useEffect是在渲染后执行的,useMemo是在渲染时期执行的,返回的值可以直接参与渲染。

useCallback

当useMemo返回的值是一个函数时,可以使用useCallback替代,即useMemo(() => fn) === useCallback(fn)

const App = () => {
  const [count, setCount] = useState(0);

  let double = useMemo(() => {
    return () => {
      return count * 2;
    };
  });
  let double2 = useCallback(() => {
    return count * 2;
  });
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Click(count:{count}, double:{double()}, double2:{double2()})
    </div>
  );
};

useRef

使用方法:const couterRef = useRef(initValue)

获取子组件或者DOM节点的句柄

const App = () => {
  const [count, setCount] = useState(0);
  const countRef = useRef();
  useEffect(() => {
    console.log(countRef.current);
  });
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
      ref={countRef}
    >
      Click(count:{count})
    </div>
  );
};

渲染周期之间共享数据的存储

const App = () => {
  const [count, setCount] = useState(0);
  const timer = useRef();

  useEffect(() => {
    timer.current = setInterval(() => {
      setCount((count) => {
        return count + 1;
      });
    }, 1000);
  }, []);
  useEffect(() => {
    if (count > 5) {
      clearInterval(timer.current);
    }
  });
  return <div>Click(count:{count})</div>;
};

自定义hook

自定义Hooks可以实现逻辑复用等,在多个组件中可以复用我们自定义的Hooks,并且里面的状态是独立的,自定义Hooks以use开头。

自定义的获取浏览器窗口的大小:

const useWinSize = () => {
  const [size, setSize] = useState({
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight,
  });
  const onResize = useCallback(() => {
    setSize({
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
    });
  }, []);
  useEffect(() => {
    window.addEventListener("resize", onResize);
    return () => {
      window.removeEventListener("resize", onResize);
    };
  }, []);
  return size;
};

Class组件与hooks的对比

Class组件的不足

1、状态逻辑复用难

缺少复用机制

属性props和高阶组件导致层级冗余

2、复杂组件难以理解

生命周期函数混杂不相干逻辑

相干逻辑分散在不同生命周期

3、this指向困扰

类成员函数不能保证this(在class中,我们必须搞清楚this的指向到底是谁,所以需要花很多的精力去学习this;虽然掌握this是必要,但是处理起来依然很麻烦)

Hooks的优势

1、函数组件无this指向问题

2、自定义hook方便复用状态逻辑

3、副作用(绑定事件、网络请求、访问DOM)的关注点分离

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Hooks是React 16.8版本中新增的特性,它提供了一种在函数组件中使用状态和其他React特性的方式。使用Hooks可以使函数组件具备类组件的功能,而不需要使用类组件的繁琐语法和复杂的生命周期方法。在实际项目中使用React Hooks可以带来更好的开发体验和代码复用。 在使用React Hooks进行实战时,可以通过useState和useEffect等Hook来处理组件中的状态和副作用。useState可以用于在函数组件中创建和管理状态,而useEffect可以用于处理副作用操作,例如发送网络请求和订阅事件等。同时,还可以使用其他常用的Hooks,比如useRef和useCallback等。 在团队协作方面,引入React Hooks可能会导致团队成员对于Hooks的水平不一致。一些常见的问题包括闭包问题和依赖死循环等。解决闭包问题可以使用不同的方法,React官方并没有给出太多的最佳实践,所以团队成员需要通过实践摸索出适合自己的方式。此外,在刚接触Hooks时,团队成员可能只熟悉useState和useEffect这两个最常用的Hooks,对于其他常用的Hooks的使用场景可能不太清楚。 为了避免一些常见的问题,可以定期在团队内分享React Hooks的最佳实践,引导团队成员更好地理解和使用Hooks。对于那些不喜欢使用React Hooks的成员,可以继续使用类组件,因为类组件在某些方面可能更容易理解和调试。React Hooks只是一种工具,会使用它会提升开发效率,但不使用也不会影响其他人的代码。因此,类组件和函数组件可以共存。 总之,React Hooks是一个强大的工具,可以在函数组件中使用状态和其他React特性。在实际项目中,使用React Hooks可以带来更好的开发体验和代码复用,但需要注意团队成员之间的水平差异和常见问题的解决方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [React hooks实战总结](https://blog.csdn.net/sinat_17775997/article/details/100014480)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [React-Hook最佳实践](https://blog.csdn.net/xiaofeng123aazz/article/details/127361597)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值