最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Prevent modal from closing after re-render in react - Stack Overflow

programmeradmin3浏览0评论

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. Because there is a change in state, everything will re-render.

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 is rendered too, as it's inside.

I have thought of two possible solutions:

  1. Move the modal outside of the ponent. 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. So, if I move the modal out from Component, I would have to pass the status and the action to change status (e.g. [open, setOpen]) through several ponents until button B (prop drilling).

  2. Another solution: On the action onButtonClick I just do the API update, and use a new state updated = true; then, onModalClose, only if updated is true, I run setState so Component is rendered just after the modal is closed. But this solution seems a hack to me. There must be a better way.

Is there any better solution?

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. Because there is a change in state, everything will re-render.

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 is rendered too, as it's inside.

I have thought of two possible solutions:

  1. Move the modal outside of the ponent. 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. So, if I move the modal out from Component, I would have to pass the status and the action to change status (e.g. [open, setOpen]) through several ponents until button B (prop drilling).

  2. Another solution: On the action onButtonClick I just do the API update, and use a new state updated = true; then, onModalClose, only if updated is true, I run setState so Component is rendered just after the modal is closed. But this solution seems a hack to me. There must be a better way.

Is there any better solution?

Share Improve this question asked Jan 11, 2021 at 17:05 de3de3 2,0006 gold badges25 silver badges42 bronze badges 1
  • Full code please. Something is fundamentally wrong with your code. – Andrew Commented Jan 11, 2021 at 17:13
Add a ment  | 

2 Answers 2

Reset to default 3

Something is obviously going very wrong here, the Modal should not close. 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.

So you have 2 options here:

1/ Keep your Modal inside your Component and use 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 ponent and use bination of memo and 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 pare if all Modal props are === from previous render, which is now the case, because memoization of onButtonClick with useCallback, and so your Modal ponent will not re-render

https://reactjs/docs/hooks-reference.html#usememo

发布评论

评论列表(0)

  1. 暂无评论