reactjs - 在 Redux 道具更改上使用 useEffect 设置本地状态
问题描述
我是 React Redux 的新手,我正在尝试使用钩子setState
在 Redux 中进行道具更改。useEffect
我有以下代码:
const DeploymentOverview = ({diagram, doSetDiagram}) => {
const { diagram_id } = useParams()
const [instances, setinstances] = useState(null)
const [error, seterror] = useState([false, ''])
useEffect(() => {
GetDiagram(diagram_id).then(d => doSetDiagram(d)).catch(err => seterror([true, err]))
}, [doSetDiagram])
useEffect(() => {
if (diagram) {
if (diagram.instances) {
let statusList = []
diagram.instances.forEach(instance => {
InstanceStatus(instance.key)
.then(status => statusList.push(status))
.catch(err => seterror([true, err]))
});
setinstances(statusList)
}
}
}, [diagram])
return (
<Container>
{error[0] ? <Row><Col><Alert variant='danger'>{error[1]}</Alert></Col></Row> : null}
{instances ?
<>
<Row>
<Col>
<h1>Deployment of diagram X</h1>
<p>There are currently {instances.length} instances associated to this deployment.</p>
</Col>
</Row>
<Button onClick={setinstances(null)}><FcSynchronize/> refresh status</Button>
<Table striped bordered hover>
<thead>
<tr>
<th>Status</th>
<th>Instance ID</th>
<th>Workflow</th>
<th>Workflow version</th>
<th>Jobs amount</th>
<th>Started</th>
<th>Ended</th>
<th></th>
</tr>
</thead>
<tbody>
{instances.map(instance =>
<tr>
<td>{ <StatusIcon status={instance.status}/> }</td>
<td>{instance.id}</td>
{/* <td>{instance.workflow.name}</td>
<td>{instance.workflow.version}</td> */}
{/* <td>{instance.jobs.length}</td> */}
<td>{instance.start}</td>
<td>{instance.end}</td>
<td><a href='/'>Details</a></td>
</tr>
)}
</tbody>
</Table>
</>
: <Loader />}
</Container>
)
}
const mapStateToProps = state => ({
diagram: state.drawer.diagram
})
const mapDispatchToProps = {
doSetDiagram: setDiagram
}
export default connect(mapStateToProps, mapDispatchToProps)(DeploymentOverview)
我在第一个 useEffect 中想要设置 de Redux 状态diagram
(这有效),然后我有另一个 useEffect 钩子,它将从名为 next 的图表属性中获取一个列表,instances
我循环遍历这些instances
并执行获取以获取该实例的状态并将此状态添加到statusList
. 最后我instances
使用setinstances(statusList)
所以现在我希望设置状态结果列表,instances
情况就是这样(也有效?)。但是随后该值又变回了初始值null
...
在我的控制台中,它首先显示空值(好的,初始值),然后是列表(是的!),然后又是空值(嗯?)。我在互联网和 useEffect 文档上阅读了 useEffect 在每次渲染后运行,但我仍然不明白为什么instances
要设置然后又回到它的初始状态。
我很好奇我做错了什么以及如何解决这个问题。
解决方案
如果你有多个异步操作,你可以使用Promise.all:
useEffect(() => {
if (diagram) {
if (diagram.instances) {
Promise.all(
diagram.instances.map((instance) =>
InstanceStatus(instance.key)
)
)
.then((instances) => setInstances(instances))
.catch((err) => setError([true, err]));
}
}
}, [diagram]);
这是一个工作示例:
const InstanceStatus = (num) => Promise.resolve(num + 5);
const useEffect = React.useEffect;
const App = ({ diagram }) => {
const [instances, setInstances] = React.useState(null);
const [error, setError] = React.useState([false, '']);
//the exact same code from my answer:
useEffect(() => {
if (diagram) {
if (diagram.instances) {
Promise.all(
diagram.instances.map((instance) =>
InstanceStatus(instance.key)
)
)
.then((instances) => setInstances(instances))
.catch((err) => setError([true, err]));
}
}
}, [diagram]);
return (
<pre>{JSON.stringify(instances, 2, undefined)}</pre>
);
};
const diagram = {
instances: [{ key: 1 }, { key: 2 }, { key: 3 }],
};
ReactDOM.render(
<App diagram={diagram} />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
你做错了以下几点:
diagram.instances.forEach(instance => {
InstanceStatus(instance.key)//this is async
//this executes later when the promise resolves
//mutating status after it has been set does not
//re render your component
.then(status => statusList.push(status))
.catch(err => seterror([true, err]))
});
//this executes immediately so statusList is empty
setinstances(statusList)
推荐阅读
- apache - Htaccess 将目录重定向到另一个但允许主文件夹 URL 保持不变
- python - 如何替换数组中的引号、括号和数字?
- amazon-web-services - 通过 S3 SignedUrl 保护 Strapi 上传文件夹
- javascript - 多页表单 html javascript
- github - 在 github 操作中更新私有子模块时的身份验证问题
- javascript - 如何在自定义钩子 react.js 中使用 React.useMemo?
- python - “NameError: name 'redirect' is not defined”即使重定向已导入
- javascript - 导航到对象属性值简写定义
- microsoft-dynamics - 从任务/作业计划程序运行报告
- micronaut - 接收一些对象并将它们转换为另一个对象的自定义 TypeConverter