与对象和嵌套数组进行状态比较

时间:2019-09-24 03:54:17

标签: reactjs react-hooks react-state-management

我试图将状态与同一对象的先前版本( useRef )进行比较,以检测更改。

使用 useEffect 加载到状态的对象如下所示:

{
  active: true,
  design: [
    {
      existing: '55Xgm53McFg1Bzr3qZha',
      id: '38fca',
      options: ['John Smith', 'Jane Doe'],
      required: true,
      title: 'Select your name',
      type: 'Selection List'
    },
   {
      existing: '55Xgm53McFg1Bzr3qZha',
      id: '38fca',
      options: ['John Smith', 'Jane Doe'],
      required: true,
      title: 'Select your name',
      type: 'Selection List'
    },
  ],
  icon: '?',
  id: '92yIIZxdFYoWk3FMM0vI',
  projects: false,
  status: true,
  title: 'Prestarts'
}


这就是我加载应用程序对象并定义比较器状态( previousApp )进行比较并检测更改的方法(使用lodash),这一切都很有效,直到我更改 design 数组。

const [app, setApp] = useState(null)
const [edited, setEdited] = useState(false)
const previousApp = useRef(null)

 useEffect(() => {
    if (app === null) {
      getApp(someAppId).then(setApp).catch(window.alert)
    }
    if (previousApp.current === null && app) {
      previousApp.current = { ...app }
    }
    if (previousApp.current && app) {
      _.isEqual(app, previousApp.current) ? setEdited(false) : setEdited(true)
    }
  }, [app])

例如,我使用以下代码更改app.design [0] .title ='testing'的输入值:

const updateItem = e => {
  let newApp = { ...app }
  let { name, value } = e.target
  newApp.design[0][name] = value
  setApp(newApp)
}

从某种意义上说,它可以更新我的应用程序状态对象,但不能检测到与 previousApp.current

相比有任何更改

更改两个值后,当我控制台登录 app previousApp 时,它们是相同的。由于某种原因,它似乎也更新了我的 previousApp 值。


重新排列 design 数组可以正常工作,并使用以下功能检测到更改:

const updateDesign = e => {
  let newApp = { ...app }
  newApp.design = e
  setApp(newApp)
}

2 个答案:

答案 0 :(得分:2)

它可能没有检测到任何差异,因为design属性中存在的 array 保持相同的引用。

执行此操作时:

let newApp = { ...app }

您正在为应用创建一个新对象,但是该对象的属性值将保持不变,因为它是一个浅表副本。因此,design 数组(它是一个对象,因此通过引用进行处理)将保持其值(引用)不变。

我认为这也可以解决您的问题:

const updateItem = e => {
  let newApp = { ...app };
  let newDesign = Array.from(app.design);  // THIS CREATES A NEW ARRAY REFERENCE FOR THE 'design' PROPERTY
  let { name, value } = e.target;
  newDesign[0][name] = value;
  setApp({
    ...newApp,
    design: newDesign
  });
}

答案 1 :(得分:0)

我发现使用lodash的cloneDeep函数可以删除previousApp和App之间发生的奇怪链接;即使我使用了{... app}

请参阅以下内容:

if (previousApp.current === null && app) {
   previousApp.current = cloneDeep(app)
}