当前位置: 首页 > article >正文

Zustand selector 发生 infinate loops的原因以及解决

Zustand selector 发生 infinate loops

做zustand tutorial project的时候,使用选择器方法引入store,出现Maximum update depth exceeded,也就是组件一直重新渲染,改成直接使用store就没有不会出现这个问题。如下:

  // const [xIsNext, setXIsNext] = useGameStore((state) => [
  //   state.xIsNext,
  //   state.setXIsNext,
  // ]);
  
  const { history, setHistory, xIsNext, setXIsNext } = useGameStore()

目前看到有关这个问题的博客很少,特此记录一下。
感谢一下我的mentor们,如此认真地教我,给我充足的时间学习

问题产生原因

官方文档的解释如下:
在这里插入图片描述
文档链接

也就是说,这是因为Zustand v5的改动,当selector返回一个新的引用,可能导致无限循环

细究了一下,问题产生原因如下:

  1. react的默认比较为引用比较,在zustandV5中沿用了这种方式。
  2. 每次重新渲染,useStore都会再执行一次,selector每次都返回的是一个新的引用
  3. zustand使用浅比较判断状态变化,触发重新渲染,以此往复

比如像下面这样使用selector

  const { history, setHistory} = useGameStore(((state) => ({
    history: state.history,
    setHistory: state.setHistory,
  })));
  const [searchValue, setSearchValue] = useStore((state) 
          => [  state.searchValue,  state.setSearchValue,])

以上两种方法selector分别返回一个对象和一个数组,每次重新渲染,其引用都会发生变化,也就触发了infinate loops

解决方法

  1. 避免在selector中返回对象
    这是我认为最直接的办法:
const history = useGameStore((state) => state.history);
const setHistory = useGameStore((state) => state.setHistory);
//不要像下面这样
//  const { history, setHistory} = useGameStore(((state) => ({
//    history: state.history,
//    setHistory: state.setHistory,
//  })));
  1. 采用文档中介绍的使用useShllow解决:
    但是useShllow比较对象只会比较最浅层的值,要注意可能产生的副作用
  const { history, setHistory, xIsNext, setXIsNext } = useGameStore(useShallow((state) => ({
    history: state.history,
    setHistory: state.setHistory,
    xIsNext: state.xIsNext,
    setXIsNext: state.setXIsNext,
  })));

附: zustand实现原理

zustand源代码中useShallow实现部分如下(也就是比较值而非比较引用):

import React from 'react'
import { shallow } from '../vanilla/shallow.ts'

export function useShallow<S, U>(selector: (state: S) => U): (state: S) => U {
  const prev = React.useRef<U>(undefined)
  return (state) => {
    const next = selector(state)
    return shallow(prev.current, next)
      ? (prev.current as U)
      : (prev.current = next)
  }
}

http://www.kler.cn/a/488628.html

相关文章:

  • Spring——自动装配
  • 微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果
  • 【网络协议】开放式最短路径优先协议OSPF详解(四)
  • C#语言的网络编程
  • OpenAI CEO 奥特曼发长文《反思》
  • [Linux]redis5.0.x升级至7.x完整操作流程
  • Unity Android AAB包GooglePlay上线备忘
  • vmware-ubuntu22.04配置虚拟机win10,重新上网成功
  • pyTorch笔记
  • 【网络】计算机网络的分类 局域网 (LAN) 广域网 (WAN) 城域网 (MAN)个域网(PAN)
  • 英伟达多维进击汽车业务:自动驾驶时代已至
  • 02-51单片机数码管与矩阵键盘
  • 分布式Id方案选择
  • NLP三大特征抽取器:CNN、RNN与Transformer全面解析
  • vue video重复视频 设置 srcObject 视频流不占用资源 减少资源浪费
  • 跟着逻辑先生学习FPGA-第六课 无源蜂鸣器发声实验
  • 解释器模式详解
  • 力扣面试题 08.09. 括号 C语言解法 回溯递归动态规划字符串
  • 当Elasticsearch索引数据量过多时,可以采取以下措施进行优化和部署
  • Django后端相应类设计
  • Flask----前后端不分离-登录
  • mysql实现对字符列第一个汉字首字母拼音进行A-Z顺序排序,使用gbk编码
  • 计算机网络之---静态路由与动态路由
  • 图像分类、目标定位与目标检测的区别详解:定义、工作原理、应用场景
  • 车联网安全--TLS握手过程详解
  • php命名空间