1

I believe I understand how the useEffect hook works, but I am having difficulties re rendering the component to update a map function when the props sent from a parent component change.

useEffect(() => console.log('mounted'), []);

My understanding is useEffect will fire the callback function when any of the values of the second argument change.

Let me show my code. I've added comments to easily explain what's happening. On a nested Child component I am calling a function from the parent to remove an item from the state. That happens just fine, and I am passing the new state down to the child component that has a map function, but that map function doesn't update. I feel like I am not using useEffect() correctly.

const Parent = (props) => {
    const [template_data, setTemplateData] = useState({});

    // called on an onChange somewhere in the Parent component.  Works fine. 
    const fetch = (e) => {
      ... 
      .then(response => {
          setTemplateData(JSON.parse(response.test_data))
      })
    }

    // Called in a nested child component
    // This is updating the state just fine.
    const removeGroupItem = (index, name ) => {
        let group = name.split('.')[1]
        const newState = template_data;
        if (index === -1) return;
        newState[group].splice(index, 1);
        setTemplateData(newState)
    }
    return (
        <DynamicForm template={template_data} removeGroupItem={(id, name) => removeGroupItem(id, name)}/>
    )
}

const DynamicForm = (props) => {
    const [ template_data, setTemplateData ] = useState({...props.template});

    // my understadning is if props change, fire callback setTemplateData(), correct? 
    useEffect(() => {
        setTemplateData(props.template)
    }, [props])

    return (
        Object.keys(template_data).map((section, index) => (
          // Passing Parent function removeGroupItem() to nested child
          <DynamicInputGroup removeGroupItem={props.removeGroupItem} {...section} key={index} />
        ))
    )
}

const DynamicInputGroup = (props) => {
    const [ state, setState ] = useState({...props});

    // Again, do I check if props from DynamicForm change fire state update? 
    useEffect(() => {
        setState(props)
    }, [props])

    return (
        <Fragment>
            // Mapping state
            {state.defaultValue.map((obj, id) => {
                return (
                  <Fragment key={id}>
                    // Mapping each object within the above map (needed for my case of response from fetch)
                      {Object.keys(obj).map((field, key) => {
                          let data = {
                              // blah blah defining some stuff
                          }
                          return (
                            <Field component={DynamicTextInput} {...data} key={data.name}/>
                          )
                      })}
                      // onClick triggers function in Parent component, I see the change in state on Parent, see the change on DynamicForm Props and State, and see the state change on this component, but no re render happens in above map.
                      {id >= 1 ? <span onClick={() => state.removeGroupItem(id, state.name)}>remove me</span> : ''}
                  </Fragment>
                )
            })}
        </Fragment>
    )
}

Thoughts? I would love to learn rather than just an answer. I am new to Hooks.

Edit: I was reading up on this, which is why I am getting confused. How to rerender component in useEffect Hook

Ryan
  • 2,144
  • 8
  • 28
  • 39

0 Answers0