反应状态与对象和嵌套数组的比较
React state comparison with objects and nested arrays
我正在尝试将状态与同一对象的先前版本 (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)
}
我发现使用 lodash 的 cloneDeep 函数我能够删除 previousApp 和 App 之间发生的奇怪 link;即使我使用了 {...app}
查看以下内容:
if (previousApp.current === null && app) {
previousApp.current = cloneDeep(app)
}
它可能没有检测到任何差异,因为 array 存在于 design
属性 中保持相同的引用。
当你这样做时:
let newApp = { ...app }
您正在为您的应用程序创建一个新对象,但该对象的 属性 值将保持不变,因为它是一个浅拷贝。因此,design
array(它是一个对象,因此通过引用处理)将保持其值(引用)不变。
我认为这也能解决您的问题:
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
});
}
我正在尝试将状态与同一对象的先前版本 (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)
}
我发现使用 lodash 的 cloneDeep 函数我能够删除 previousApp 和 App 之间发生的奇怪 link;即使我使用了 {...app}
查看以下内容:
if (previousApp.current === null && app) {
previousApp.current = cloneDeep(app)
}
它可能没有检测到任何差异,因为 array 存在于 design
属性 中保持相同的引用。
当你这样做时:
let newApp = { ...app }
您正在为您的应用程序创建一个新对象,但该对象的 属性 值将保持不变,因为它是一个浅拷贝。因此,design
array(它是一个对象,因此通过引用处理)将保持其值(引用)不变。
我认为这也能解决您的问题:
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
});
}