简体   繁体   English

防止模态在反应中重新渲染后关闭

[英]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:我想到了两种可能的解决方案:

  1. 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(道具钻孔)。

  2. 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移到组件之外,并结合使用memouseCallback

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 的onButtonClickuseCallback ,所以你的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.

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