react,antd,typescript
为什么在Modal.confirm后,前面update()方法设置的值没有成功,在getRow()方法里面获取的还是原来的值
import { Button, Modal } from 'antd';
import React, { useState, useEffect, useRef } from 'react';
function PageComponent() {
const [person, setPerson] = useState({
age: "1",
name: "张三"
});
const msgDialog = async (msg: string, bShowCanBtn: boolean = true):Promise<{modal : ReturnType<typeof Modal.confirm> , status : true | false}> => {
return new Promise((resolve, reject) => {
const modal = Modal.confirm({
title: "test",
content: <h4>{msg}</h4>,
closable: true,
okText: "确定",
cancelText: "取消",
cancelButtonProps: { style: { display: bShowCanBtn == false ? "none" : "inline" } },
centered: true,
onOk() {
resolve({modal , status : true});
},
onCancel() {
resolve({modal , status : false});
},
})
})
};
const cmd_update = async () => {
let instance = await msgDialog('是否更新?')
if(!instance?.status) {
instance?.modal.destroy();
return;
}
await update();
let retInstance = await msgDialog('成功登录!', false);
if(!retInstance?.status) {
retInstance?.modal.destroy();
return;
}
await getRow();
}
const update = async () => {
const obj = {age: "2", name: "李四"};
setPerson((form) => ({ ...form, ...obj }));
};
const getRow = async () => {
console.info("getRow=", person.age, person.name)
};
useEffect(() => {
console.info("useEffect=", person.age, person.name)
getRow();
}, [person.age, person.name]);
return (
<div>
<Button onClick={cmd_update}>更 新</Button>
</div>
);
}
export default PageComponent;
怎么样才能在getRow方法里面获取update()方法里面设置的值?
这是闭包引起的,我只说解决方案。我给你提供三种。
1: 是使用 useEffect
function PageComponent() {
const [person, setPerson] = useState({
age: "1",
name: "张三"
});
const msgDialog = async (msg: string, bShowCanBtn: boolean = true): Promise<{ modal: ReturnType<typeof Modal.confirm>, status: true | false }> => {
return new Promise((resolve, reject) => {
const modal = Modal.confirm({
title: "test",
content: <h4>{msg}</h4>,
closable: true,
okText: "确定",
cancelText: "取消",
cancelButtonProps: { style: { display: bShowCanBtn == false ? "none" : "inline" } },
centered: true,
onOk() {
resolve({ modal, status: true });
},
onCancel() {
resolve({ modal, status: false });
},
})
})
};
const cmd_update = (async () => {
let instance = await msgDialog('是否更新?')
if (!instance?.status) {
instance?.modal.destroy();
return;
}
await update();
// let retInstance = await msgDialog('成功登录!', false);
// if (!retInstance?.status) {
// retInstance?.modal.destroy();
// return;
// }
// await getRow();
})
const update = async () => {
const obj = { age: "2", name: "李四" };
setPerson((form) => ({ ...form, ...obj }));
};
const getRow = () => {
console.info("getRow=", person.age, person.name)
}
useEffect(() => {
// 更新后的逻辑放在 useEffect中
async function next() {
let retInstance = await msgDialog('成功登录!', false);
if (!retInstance?.status) {
retInstance?.modal.destroy();
return;
}
await getRow();
}
next();
}, [person]);
return (
<div>
<Button onClick={cmd_update}>更 新</Button>
</div>
);
}
2:更新函数返回 更新后的状态
function PageComponent() {
const [person, setPerson] = useState({
age: "1",
name: "张三"
});
const msgDialog = async (msg: string, bShowCanBtn: boolean = true): Promise<{ modal: ReturnType<typeof Modal.confirm>, status: true | false }> => {
return new Promise((resolve, reject) => {
const modal = Modal.confirm({
title: "test",
content: <h4>{msg}</h4>,
closable: true,
okText: "确定",
cancelText: "取消",
cancelButtonProps: { style: { display: bShowCanBtn == false ? "none" : "inline" } },
centered: true,
onOk() {
resolve({ modal, status: true });
},
onCancel() {
resolve({ modal, status: false });
},
})
})
};
const cmd_update = (async () => {
let instance = await msgDialog('是否更新?')
if (!instance?.status) {
instance?.modal.destroy();
return;
}
const assignPerson = await update();
let retInstance = await msgDialog('成功登录!', false);
if (!retInstance?.status) {
retInstance?.modal.destroy();
return;
}
await getRow();
})
// update函数更新完返回 最新的状态
const update = async () => {
const obj = { age: "2", name: "李四" };
return new Promise((resolve) => {
setPerson((form) => {
const assignPerson = { ...form, ...obj };
resolve(assignPerson);
return assignPerson;
});
})
};
const getRow = () => {
console.info("getRow=", person.age, person.name)
}
return (
<div>
<Button onClick={cmd_update}>更 新</Button>
</div>
);
}
3: 利用 useRef 这个我不多赘述了,不怎么推荐。
你的这个弹框业务的复杂度不高的话 可以使用 update 不用重复生成弹框实例
function PageComponent() {
const [person, setPerson] = useState({
age: "1",
name: "张三"
});
const msgDialog = async (msg: string, bShowCanBtn: boolean = true): Promise<{ modal: ReturnType<typeof Modal.confirm>, status: true | false }> => {
return new Promise((resolve) => {
const modal = Modal.confirm({
title: "test",
content: <h4>{msg}</h4>,
// closable: true,
okText: "确定",
cancelText: "取消",
cancelButtonProps: { style: { display: "inline" } },
// centered: true,
okCancel: false,
onOk: () => {
resolve({ modal, status: true });
// 组织关闭弹框
return true;
},
onCancel: () => {
resolve({ modal, status: false });
},
})
})
};
const cmd_update = async () => {
let instance = await msgDialog('是否更新?')
if (!instance?.status) {
instance?.modal.destroy();
return;
}
console.log('等待点击是');
// 点击是
instance.modal.update({
okCancel: false,
content: <h4>成功登录!</h4>,
cancelButtonProps: {
style: { display: "none" }
},
okButtonProps: {
onClick: () => {
instance.modal.destroy();
}
}
})
console.log(instance);
}
return (
<div>
<Button onClick={cmd_update}>更 新</Button>
</div>
);
}
在React中,状态的更新是异步的,这意味着setPerson
函数在调用后不会立即更新person
状态的值。相反,React会安排一次状态更新,并在下一个渲染周期中反映这个变化。因此,直接在调用setPerson
之后尝试读取person
状态的值可能仍然会得到旧的值。
在你的代码中,getRow
函数是在update
函数调用后立即调用的,但由于状态的异步更新特性,此时person
状态可能还没有更新。然而,你已经通过useEffect
钩子正确地设置了依赖项,以便在person
状态发生变化时重新运行getRow
。
但是,在cmd_update
函数中,你尝试在update
和getRow
之间立即同步地等待状态更新,这是不可能的。你应该依赖useEffect
来在状态更新后重新运行getRow
,而不是在cmd_update
函数中直接调用它。
不过,如果你想在cmd_update
函数中确保getRow
在update
之后调用,并且确保使用的是更新后的person
状态值,你可以使用useRef
来保存一个对person
的引用,并在update
函数中更新它。但请注意,这并不是一个好的实践,因为它会绕过React的状态管理。更好的方法是依赖于React的状态更新机制,并使用useEffect
钩子来监听状态变化。
然而,在你的例子中,你可以简单地从useEffect
钩子中删除getRow
的调用,因为它已经在状态更新时自动运行了。另外,你可以删除getRow
函数中的await
关键字,因为它不是异步函数,也不应该被当作异步函数使用。
修改后的代码如下:
// ...
useEffect(() => {
console.info("useEffect=", person.age, person.name);
// 这里已经足够,不需要在cmd_update中直接调用getRow
}, [person]);
const cmd_update = async () => {
let instance = await msgDialog('是否更新?');
if (!instance?.status) {
instance?.modal.destroy();
return;
}
await update();
// 这里不需要再调用getRow,因为useEffect会在person状态更新后自动运行它
let retInstance = await msgDialog('成功登录!', false);
if (!retInstance?.status) {
retInstance?.modal.destroy();
return;
}
// 如果需要在cmd_update之后立即执行某些操作,并且这些操作依赖于新的person状态,
// 你应该考虑将这些操作放在另一个useEffect钩子中,或者重新设计你的组件逻辑。
};
// ...
const getRow = () => {
// 不再是异步函数,也不需要await
console.info("getRow=", person.age, person.name);
};
// ...
这样,每当person
状态更新时,useEffect
都会运行,并且getRow
函数会打印出更新后的值。
问题内容: 我的结构如下所示: 组件3应该根据组件5的状态显示一些数据。由于道具是不可变的,我不能简单地将其状态保存在组件1中并转发它,对吗?是的,我已经阅读了有关redux的内容,但不想使用它。我希望有可能通过反应来解决。我错了吗? 问题答案: 对于孩子与父母的通信,您应该传递一个将状态从父母设置为孩子的函数,如下所示 这样,孩子可以通过调用通过props传递的函数来更新父母的状态。 但是您将不
用的是 React 和 Antd v5 为什么在改了 state 之后元素还是没变化呢 问过 GPT 但是没有结果
假设,我有如下 concurrentHashMap 代码: 此 方法是从多个线程调用的,可以尝试同时更新同一 accountId 的数量。 如何确保currentBalance在< code>get和< code>put之间不发生变化?因为根据我的理解,如果线程在执行< code>get后抢占,同时其他线程更新余额,< code>put将使用旧余额执行更新。
问题内容: 我正在尝试仅更新数组状态中的一个元素,但不确定如何执行此操作。 State 设定状态 如果我想更改标记的第四个元素中的键,该怎么做? 谢谢 问题答案: 重要的一点是,我们不应该直接更改状态数组,而要始终在新数组中进行更改,然后使用setState更新状态值。 如 Doc 建议: 切勿直接更改this.state,将this.state视为不可变。 更新状态数组的基本流程是: 1- 首先
问题内容: 我试图通过使用这样的嵌套属性来组织我的状态: 但是像这样更新状态 不起作用。如何正确完成? 问题答案: 为了创建嵌套对象,您可以按照以下方法进行操作,因为我认为setState无法处理嵌套更新。 这个想法是创建一个虚拟对象,对其执行操作,然后用更新的对象替换组件的状态 现在,散布运算符仅创建对象的一级嵌套副本。如果您的状态是高度嵌套的,例如: 您可以在每个级别使用传播运算符来设置状态,