React Hook 遇到的小坑--持续记录

浅浅的花香味﹌ 2023-02-16 04:11 86阅读 0赞

1. 依赖项没指定好

hook是利用闭包的特性来生成对应的方法;

当不传依赖项,方法内部的状态值都是取的在定义hook的初始值;
当传入了依赖项,那么依赖项值发生改变,hook会被更新,这个时候它内部用的变量也都会更新到最新。

所以,如果hook里用了状态变量,一定要记得作为依赖项传入,否则会遇到坑哦。
尤其是hook之间互相调用的时候,很容易指定不好依赖项。

如下例子:

本意:merchantChartQuery作为fetchOrder的依赖项,控制fetchOrder的更新。当执行setCpsOrderStatus方法的时候,调用fetchOrder的方法,利用最新的数据来查询接口。

结果:merchantChartQuery更新后,执行setCpsOrderStatus方法时,fetchOrder还是用了旧的数据去查询接口。

  1. // props里传入merchantChartQuery作为查询参数
  2. const View: React.FunctionComponent = props => {
  3. // 从props里取一个变量
  4. const { merchantChartQuery } = props;
  5. // 利用最新的merchantChartQuery数据去接口查询数据
  6. const fetchOrder = useCallback(params => {
  7. fetchMerchantOrderData({
  8. page: 1,
  9. ...merchantChartQuery,
  10. ...params
  11. });
  12. }, [merchantChartQuery]);
  13. // 错误写法
  14. // 这里不写依赖项时,虽然上面fetchOrder更新里,
  15. // 但是这里取得还是旧的fetchOrder,导致查询时仍然用的就数据查询
  16. const setCpsOrderStatus = useCallback(cpsOrderStatus => {
  17. fetchOrder({ cpsOrderStatus });
  18. }, []);
  19. // 正确写法
  20. const setCpsOrderStatus = useCallback(cpsOrderStatus => {
  21. fetchOrder({ cpsOrderStatus });
  22. }, [fetchOrder]);
  23. }

2. hook利用Object.is来判断依赖项是否更新

hook判断一个依赖项是否发生更新,利用的是Object.is方法(内部是===来对比);
基本类型变量的比较基本不会有什么困扰,引用类型就需要注意了。

如下例子:

本意:根据用户的权限不用,reportTabs数组(控制页面导航的显示内容)也是不同的,希望在useEffect中通过权限查询结果来更新数组内容。这样不同权限的用户会看到不同的导航内容。

结果:由于useState中使用了initReportTabs作为初始值,获得权限后更新时也是通过引用initReportTabs来处理的,导致Object.is在比较的时候,认为变量没有改变,不会更新组件,会导致页面显示与实际数据不符。

  1. interface IReportTabTypes {
  2. key: string;
  3. title: string;
  4. }
  5. // reportTabs的初始值
  6. const initReportTabs = [
  7. {
  8. key: 'goods-overview',
  9. title: '商品佣金报表',
  10. }
  11. ];
  12. const View: React.FunctionComponent = () => {
  13. const [reportTabs, setReportTabs] = useState<IReportTabTypes[]>(initReportTabs);
  14. useEffect(() => {
  15. merchantApi.fetchIsTuanV2Header().then(res => {
  16. // 引用类型的变量,指向的是同一个内存变量
  17. const list = initReportTabs;
  18. res && list.push({
  19. key: 'merchant-overview',
  20. title: '团长佣金报表',
  21. });
  22. // 无效写法
  23. setReportTabs(list);
  24. // 有效写法,传入的是一个新的变量,hook认为他是发生更新,进而会更新组件
  25. setReportTabs([...list]);
  26. });
  27. }, []);
  28. }

3. hook内是一个闭包

如下例子:
本意:通过按钮事件,控制弹框展示,弹框内是一个异步加载的级联选择框。
结果: 弹框里的级联选择框内容并没有随着数据的更新而实时展示出来

  1. const View: React.FunctionComponent = () => {
  2. // 级联选择框的选项列表
  3. const [categoryList, setCategoryList] = useState<any[]>([]);
  4. // 级联选择框异步加载的方法
  5. const onLoadMore = useCallback(option => {
  6. option.loading = true;
  7. // 异步查询子类数据,更新categoryList特定项的children数组内容
  8. api.listChildren({
  9. pid: option.id,
  10. channel: 1,
  11. }).then(data => {
  12. option.children = data.map(item => {
  13. return {
  14. ...item,
  15. isLeaf: true,
  16. };
  17. });
  18. }).finally(() => {
  19. option.loading = false;
  20. const list = [ ...categoryList ];
  21. setCategoryList(list);
  22. });
  23. }, [categoryList]);
  24. // 调用handleOpenDialog方法后,创建一个弹框,这个时候的弹框是在一个闭包中,外部数据更新只是能引起handleOpenDialog方法的更新,弹框中的状态无法被改变
  25. // 所以虽然接口请求到了新的数据,categoryList发生了更新,但是级联框的内容依然是旧的
  26. const handleOpenDialog = useCallback(() => {
  27. Dialog.open({
  28. title: '选择类目',
  29. content: <Cascader
  30. filterable={ true}
  31. value={ item.ids}
  32. options={ categoryList}
  33. loadMore={ onLoadMore}
  34. propsAlias={ { label: 'name', id: 'id'}}
  35. />
  36. footer:
  37. })
  38. }, [categoryList]);
  39. return (
  40. <div>
  41. <button onClick={ handleOpenDialog}>显示弹窗</button>
  42. </div>
  43. )
  44. }

发表评论

表情:
评论列表 (有 0 条评论,86人围观)

还没有评论,来说两句吧...

相关阅读

    相关 React Hook

    -------------------- Hook简介 1. Hook专门用于增强函数组件的功能(Hook在类组件中是不能使用的),使之理论上可以成为类组件的替代品