React updating UI after a change in Props feeded to useReducer

Viewed 814

I have a React Functional Component that behaves in this way:

const Child = ({objValues, number}) => {

  const emptyState = {
    a: { b: "", c:""}
    d: { e: "", f:""}
  }
  const initialState = {...emptyState, ...objValues}
  const [state, dispatch] = useReducer(reducer, {...initialState})
  
  return (
   // render something based on state's nested objects.
   // and the number prop.
  )
}



const Parent = () => {
  [objValues, setObjValues] = useState({});
  [number, setNumber] = useState("");

  //... some network requests to populate values
  // and change number (using setState);

  useEffect(() => {
    // fetchAPI and then set values using spread operator
    // to force creating a new object.
    setObjValues({...values})
  }, [number])

  return ( <Child objValues={objValues} number={number}/>

I always get unique items (number, objValues) from the API I am using. Inside the component, I see that whenever I fire a new network request, the value of number gets updated in the UI, but the objValues shows the same values as the previous object. In the Component tabs in the react dev tools, I see that these values do update, nevertheless the UI stays the same.

2 Answers

Couple of things

  1. do not use the spread everywhere, dont see a reason for any of them in your code, if you pass object to setState it will take the current value and put it to state as value not reference so no reason to "force"
  2. try typescript or try to not mix types, in your numer state you have default value a string, either have it empty, null or something that is close to a number
  3. To your problem: since the reducer will resolve data, I dont think it has to update based on change in its initial data, what you should do, is ditch this populating some data and mixing them with redux data, but make the api request and once its done, save the data to redux and your reducer in another component will update itself
  4. EDIT: Iam dumb its not useSelector from redux, regardless initial data got to be used only once, and they dont force the hook to update its value, basicaly any solid library for react or react itself, will look at initial data only when its called the first time, and then it doesnt matter how many times or how hard you change the initial data, it shouldnt affect it (most component or form libraries do follow this rule), basically in this case I would do useeffect and I would update the reducer with the data, or if that is not possible declare new constant, where you spread your default value and then spread your reducer data
const Child = ({objValues, number}) => {

  const emptyState = {
    a: { b: "", c:""}
    d: { e: "", f:""}
  }
  const initialState = {...emptyState, ...objValues}
  const [state, dispatch] = useReducer(reducer, {...initialState})
  
  useEffect(()=>{
    dispatch({
      ...objValues
    })
  },[objValues])
  
  return (
   // render something based on state's nested objects.
   // and the number prop.
  )
}
Related