reactjs zustand状态更新,即使只有部分状态被更改

ssm49v7z  于 2023-03-12  发布在  React
关注(0)|答案(2)|浏览(219)

我有一个React测试应用程序,使用Zustand作为商店。该应用程序只显示一个输入字段,但每次字段的值被更新,整个应用程序被刷新。我一定是做了一些愚蠢的商店,但似乎没有找到什么。任何帮助将不胜感激。

import React, { useEffect } from 'react'
import { create } from 'zustand'
import { v4 as uuidv4 } from 'uuid';

const store = create((set, get) => ({
  currentPage: { blocks: [] },
  blocksForCurrentPage: [],
  findBlockById: blockId => get().blocksForCurrentPage.find(block => block.blockId === blockId),
  _addDummyBlockAtEndOfPage: _ => {
    const newDummyBlock = ({blockId: uuidv4(), content:'', type:undefined, isDummy: true})
    set(state => ({ blocksForCurrentPage: [...state.blocksForCurrentPage, newDummyBlock] }))
    set(state => ({ currentPage: { ...state.currentPage, blocks: [...state.currentPage.blocks, newDummyBlock.blockId] } }))
  },
  initCurrentPage: _ => {
    const blocks = get().currentPage?.blocks
    const lastBlockId = blocks.length > 0 ? blocks[blocks.length - 1] : undefined
    if (lastBlockId === undefined || !get().findBlockById(lastBlockId)?.isDummy) get()._addDummyBlockAtEndOfPage()
  },
  updateBlock: ({ blockId, type, content }) => {
    //update the block content
    const index = get().blocksForCurrentPage.findIndex(block => block.blockId === blockId)
    if (index < 0) return
    
    set(state => {
      const block = state.blocksForCurrentPage[index]
      const newArray = [...state.blocksForCurrentPage]
      newArray.splice(index, 1, { ...block, type, content, isDummy: false })
      return {blocksForCurrentPage: newArray}
    })
  },
}))

function App () {
  const { currentPage, initCurrentPage, updateBlock } = store((state) => ({
      currentPage: state.currentPage,
      initCurrentPage: state.initCurrentPage,
      updateBlock: state.updateBlock,
    }))
  
  console.log('Redraw app')

  useEffect(() => {
    console.log('in use event')
    initCurrentPage()
  }, [currentPage])
  
  const onChange = (t, blockId) => {
    updateBlock({ blockId, content: t.target?.value  })
  }
  
  return <>{currentPage?.blocks?.map((blockId) => <input key={blockId}
    onChange={t => onChange(t, blockId)}/>)}</>
}

export default App;

输出打印一次“使用中事件”,预计只会出现一次,效果很好。但是,每次我在输入框处于焦点状态时按下一个键,“重绘应用程序”就会打印出来。
现在,每当输入的值发生变化时,我都会更新blocksForCurrentPage数组中的一个项,但正如您所看到的,渲染只依赖于currentPage,而不依赖于blocksForCurrentPage。
对于那些愿意在这里提供帮助的人来说,是package.json文件

{
  "name": "webclient",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "immer": "^9.0.19",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "uuid": "^9.0.0",
    "zustand": "^4.3.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
yhuiod9q

yhuiod9q1#

算了吧,刚搬到MOBX 1000000x比zustand更容易理解的作品就像一个魅力

s5a0g9ez

s5a0g9ez2#

为了将来的参考,我相信你需要传入'shallow'。你正在重新渲染一个没有稳定引用的对象,所以每次渲染都是新的。

const { currentPage, initCurrentPage, updateBlock } = store((state) => ({
      currentPage: state.currentPage,
      initCurrentPage: state.initCurrentPage,
      updateBlock: state.updateBlock,
    }, shallow))

or a longer version

  const currentPage = store((state) => state.currentPage);
  const initCurrentPage = store((state) => state.initCurrentPage);
  const updateBlock = store((state) => state.updateBlock);

相关问题