react hooks, cant updating state via props

useeffect
react hooks props
usereducer
react lifecycle hooks
react hooks update state when props change
react custom hooks
react hooks uselayouteffect
react hooks on load

trying to update state variable('visible') via internal function(setVisible) in component. I checked the tutorıal and did same but its not updating after initialization of state. Sandobx link here.

props.visible is true when user click ShowModal button. but value of visible in function component is still false. (I have checked the content on debugger)

code:

import Modal from '../Helpers/AppModal'

    class Streams extends Component {
        constructor(props) {
            super(props)
            this.state = { showModal: false }
        }

        componentDidMount() {
            this.props.getStreams()
        }

        showDeleteModal = (isShow) =>
        {
            this.setState({ showModal: isShow });
        }
        onClickBackdrop = () => {this.setState({ showModal: false });}

        render() {
            return (
                <div>
                    <button onClick={()=> this.showDeleteModal(true)} className="btn btn-danger">Delete</button>

                    <Modal visible={this.state.showModal} onClickBackdrop={this.onClickBackdrop} />
                </div>
            )
        }
    }

AppModal.js:

 const AppModal = (props) => {
  const [visible, setVisible] = useState(props.visible)
  useEffect(() =>{
    setVisible(props.visible)
},[props.visible])

  debugger
  return (
    <Modal visible={visible} fade={true} onClickBackdrop={props.onClickBackdrop}>
            <div className="modal-header">
              <h5 className="modal-title">{props.title}</h5>
            </div>
            <div className="modal-body">
              {props.body}
            </div>
            <div className="modal-footer">
            <React.Fragment>
              <button type="button" className="btn btn-default" onClick={()=>setVisible(false)}>
                Close
              </button>
            </React.Fragment>

            </div>
          </Modal>
  )
}

The argument passed to useStateis just the initial state. Pass a prop to it doesn't mean that the state will be synchronized with props. You can setup an effect to mirror those changes into your local state.

Currently your Modal only see visible from the local state, changing the props value won't cause Modal to change

//Inside child
useEffect(() =>{
    setVisible(props.visible)
},[props])

Why should I use props instead of props.visible there?

The dependencies array exists to keep synchronicity, you're telling react:

"Hey, everytime one of those values changes re run this effect."

The problem is that React performs a shallow comparison (Object.is) between old and new props, uppon each render a new props object is generated which is what is triggering your effect in the first place.

React doesn't know how to "react" to nested changes. What is really changing here is props, react doesn't know (and doesn't care) about props.visible, passing it as a dependency is the same as passing []

Actually passing props as dependency is useless, since props changes every render you can omit the dependencies array, which will trigger the effect on each render

useEffect(() => {
    setVisible(props.visible)
})

Using the State Hook – React, Component { constructor(props) { super(props); this.state = { count: 0 } For example, useState is a Hook that lets you add React state to function components . In a function component, we have no this , so we can't assign or read this.state . Instead It returns a pair of values: the current state and a function that updates it. How to sync props to state in React Hooks. This is perfect use case for useEffect. Whenever props change, we will set the state inside useEffect. Lets change the example and see, useEffect( () => { setProfileState(props); }, [props]);

visible is a boolean.

Try changing the way you call setVisible like so:

setVisible(false)

instead of

setVisible({visible:false})

Prop updates updating state in hooks · Issue #14830 · facebook/react, More of a question / discussion as I could not find it in the documentation. What is the current behavior? Currently when using hooks like useState  I have a React app, where props from a parent component are passed to a child component and the props then set the state on the child. After I send an updated value to the parent component, the child component isn't updating the state with the updated props.

If this is a toggle switch then you should do this:

onClick={() => setVisible(!visible)}

Then it'll toggle on/off correctly.

You might want to set the initial value more explicitly though:

const [visible, setVisible] = useState(false);

Reacting to Prop Changes in a React Component, When building a component using React there is often a requirement to create the DOM, updating some component state, or any number of things. hook can also be used to store a mutable variable that will not trigger an  January 1, 2020 4 min read 1253. Accessing the previous props or state from within a functional component is one of those deceptively simple problems you’ll likely face as you work with React Hooks. There’s currently no React Hook that does this out of the box, but you can manually retrieve either the previous state or props from within a functional component by leveraging the useRef hook.

Beware of these traps on state and props management using react , Tagged with react, hooks. The TagList component state data have been updated, but props data State changed but no update was triggered the same reference is detected, thus re-render operation is not triggered. useState setter doesn't provide a callback after state update is done like setState does in React class components. In order to replicate the same behaviour, you can make use of the a similar pattern like componentDidUpdate lifecycle method in React class components with useEffect using Hooks

React Hooks cheat sheet: Unlock solutions to common problems , React Hooks cheat sheet: Unlock solutions to common problems Note that you have to pass the entire object to the useState updater function because the object is replaced, not merged. // Multiple state objects updated via a state object variable. Consumer and the render props API it exposes. > If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.) > Note that React may still need to render that specific component again before bailing out.

How to get previous props/state with React Hooks, A tutorial on how to get previous props/states with React Hooks Well, to understand what's going on, let's walk through the execution of the aforementioned which would be 0 — not 1 since the ref object isn't updated yet. On this page we’ve learned about one of the Hooks provided by React, called useState. We’re also sometimes going to refer to it as the “State Hook”. It lets us add local state to React function components — which we did for the first time ever! We also learned a little bit more about what Hooks are.

Comments
  • I think you should try like this: setVisible(false)
  • @SouvikGhosh did bvut still have issue
  • when I did this, it works fine for first click but not shows the modal after close and reclick the button
  • Can you post an example in a sandbox? You don't actually need useState here, but I'm assuming that your want to use it right?
  • Yes, I have created sandbox, hope it helps; codesandbox.io/embed/interesting-haze-wb2vw?fontsize=14
  • That was my mistake. I've passed props.visible as dependency, but you should pass props. updated the answer
  • Updated the answer
  • done, but issue still here, I edited post(AppModal.js)
  • FYI by setting it to false on the onClick it will only ever work once. This is why I suggested setting it to false initially and then using the !visible flag in the onClick().
  • @TyForHelpDude In your code you refer to <Modal> but appmodal.js has it listed as AppModal - maybe alter the code to refer to it correctly?
  • its just an alias