[英]Prevent modal from closing after re-render in react
Inside a Component, I have a Modal from which the user can do an update to some data through an API and then change the state of that main Component.在组件内部,我有一个模式,用户可以从中通过 API 更新某些数据,然后更改该主要组件的 state。 Because there is a change in state, everything will re-render.因为 state 有变化,所以一切都会重新渲染。
I would like to keep the modal open, so that I can show a success message.我想保持模式打开,以便显示成功消息。
The code would be something like this.代码将是这样的。
const Main = () => {
const [state, setState()] = useState();
return (
<Component state={state}>
<Modal onButtonClick={() => {
updateThroughApi().then(() => setState())} />
</Component>
)
}
When user clicks on modal's button, the state changes, and Component
is re-rendered.当用户点击 modal 的按钮时,state 发生变化,并且Component
被重新渲染。 Modal is rendered too, as it's inside.模态也被渲染,因为它在里面。
I have thought of two possible solutions:我想到了两种可能的解决方案:
Move the modal outside of the component.将模态移到组件之外。 This is a problem, as my actual code is not as simple as the example I posted.这是一个问题,因为我的实际代码并不像我发布的示例那么简单。 In my code, the modal opens on the click of a button B
, which is deep inside Component
.在我的代码中,模式在单击按钮B
时打开,该按钮位于Component
内部。 So, if I move the modal out from Component
, I would have to pass the status and the action to change status (eg [open, setOpen]) through several components until button B (prop drilling).因此,如果我将模态从Component
移出,我将不得不通过几个组件传递状态和操作以更改状态(例如 [open, setOpen]),直到按钮 B(道具钻孔)。
Another solution: On the action onButtonClick
I just do the API update, and use a new state updated = true
;另一个解决方案:在onButtonClick
操作上,我只更新 API,并使用新的 state updated = true
; then, onModalClose
, only if updated is true, I run setState
so Component
is rendered just after the modal is closed.然后, onModalClose
,只有当 updated 为真时,我才运行setState
,以便在模态关闭后立即呈现Component
。 But this solution seems a hack to me.但是这个解决方案对我来说似乎是一个黑客。 There must be a better way.一定会有更好的办法。
Is there any better solution?有没有更好的解决方案?
Something is obviously going very wrong here, the Modal should not close.这里显然出了点问题,Modal 不应该关闭。 As a workaround you could do something like this:作为一种解决方法,您可以执行以下操作:
const Main = () => {
const [state, setState()] = useState();
const modal = useMemo(() => (
<Modal onButtonClick={() => {
updateThroughApi().then(() => setState())} />
), [])
return (
<Component state={state}>{modal}</Component>
)
}
Your Modal
is re-rendering because your function passed as onButtonClick
is redefined at every render.您的Modal
正在重新渲染,因为您的 function 作为onButtonClick
传递在每次渲染时都会重新定义。
So you have 2 options here:所以你在这里有两个选择:
1/ Keep your Modal
inside your Component and use useMemo
1/ 将Modal
保存在 Component 中并使用useMemo
import { useMemo } from 'react'
const Main = () => {
const [state, setState] = useState();
const modal = useMemo(() => (
<Modal onButtonClick={() => (
updateThroughApi().then(() => setState())
)}
/>
), [])
return (
<Component state={state}>
{modal}
</Component>
)
}
Or 2/ Move your Modal
outside your component and use combination of memo
and useCallback
或者 2/ 将Modal
移到组件之外,并结合使用memo
和useCallback
import { memo, useCallback } from 'react'
const Main = () => {
const [state, setState] = useState();
const onButtonClick = useCallback(() => updateThroughApi().then(() => setState()), []);
return (
<Component state={state}>
<Modal onButtonClick={onButtonClick} />
</Component>
)
}
const Modal = memo(({onButtonClick}) => {
})
So in this case, at every render, memo
will compare if all Modal
props are ===
from previous render, which is now the case, because memoization of onButtonClick
with useCallback
, and so your Modal
component will not re-render因此,在这种情况下,在每次渲染时, memo
都会比较所有Modal
道具是否===
来自上一次渲染,现在是这种情况,因为 onButtonClick 的onButtonClick
与useCallback
,所以你的Modal
组件不会重新渲染
https://reactjs.org/docs/hooks-reference.html#usememo https://reactjs.org/docs/hooks-reference.html#usememo
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.