简体   繁体   English

React state 与对象的比较和嵌套的 arrays

[英]React state comparison with objects and nested arrays

I am trying to compare state against a previous version of the same object ( useRef ) to detect for changes.我正在尝试将 state 与相同 object ( useRef ) 的先前版本进行比较以检测更改。

The object that loads into state with useEffect looks like this:使用 useEffect 加载到 state 的object如下所示:

{
  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'
}


This is how I load in my app object and define a comparitor state ( previousApp ) to compare it and detect changes (with lodash) this all works great until I change a value in the design array.这就是我在我的应用程序 object 中加载并定义一个比较器 state ( previousApp )来比较它并检测更改(使用 lodash)的方式,这一切都很好,直到我更改设计数组中的一个值。

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])

For example I change the input value of app.design[0].title = 'testing' with the following code:例如,我使用以下代码更改 app.design[0].title = 'testing' 的输入值:

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

This works in the sense that it updates my app state object but not that it detects any changes in comparison to previousApp.current这在某种意义上有效,它更新了我的应用程序 state object 但它检测到与previousApp.current相比没有任何变化

When I console log app and previousApp after changing both values, they are identical.当我在更改两个值后控制台 log apppreviousApp时,它们是相同的。 Its seems to update my previousApp value aswell for some reason.由于某种原因,它似乎也更新了我的previousApp值。


Rearranging the design array works as expected and detects a change with the following function:重新排列设计数组按预期工作,并使用以下 function 检测更改:

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

It probably wasn't detecting any difference because the array present in the design property was keeping the same reference.它可能没有检测到任何差异,因为design属性中存在的数组保持相同的引用。

When you do this:当你这样做时:

let newApp = { ...app }

You're creating a new object for your app, but the property values of that object will remain the same, because it's a shallow copy.您正在为您的应用程序创建一个新的 object,但该 object 的属性值将保持不变,因为它是一个浅拷贝。 Thus, the design array (which is an object, and therefore is handled by reference) will keep its value (the reference) unaltered.因此, design数组(这是一个 object,因此由引用处理)将保持其值(引用)不变。

I think this would also solve your problem:我认为这也可以解决您的问题:

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
  });
}

I found that using lodash's cloneDeep function i was able to remove the strange link that was occuring between previousApp and App;我发现使用 lodash 的 cloneDeep function 我能够删除出现在 previousApp 和 App 之间的奇怪链接; Even though I used {...app}即使我使用 {...app}

See the following:请参阅以下内容:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM