Search code examples
javascriptreactjsstatedestructuring

How to destructure an object that is stored as a state value


Within a React App component, I am calling an API and storing the response within a local state. I then want to destructure the object that is stored in that state, but I can't just destructure right below the useEffect because it will throw an error before the call is completed.

Also, I don't want to break up the object within the useEffect, because I want the entire response for other things.

Here is an example:

const MyComponent = () => {

  const [calledObj, setCalledObj] = useState({})

  useEffect(() => {
    //Calling API here and setting object response as calledObj State
    setCalledObj(apiResponse)
  }, []);

  //This will throw an error when the API response has not been sent back yet.//
  // While this would be easy to write the whole path in the return, the actual path is really long.//
  const { name } = calledObj.person

  return (<div>{name}</div>)
}

Where can I destructure or how can I work around this?


Solution

  • You can use optional chaining and/or the nullish coelescing operator to work around it.

    Note: IE doesn't support either of these, but babel will polyfill them.

    const { name } = calledObj?.person ?? {};
    
    1. The optional chaining (the ?. in calledObj?.person) prevents it from blowing up if calledObj is undefined.
    2. The nullish coalescing operator (??) returns {} if calledObj.person isn't there.

    With this combination the right side is guaranteed to evaluate to an object, so the destructuring on the left never blows up.

    let calledObject; // undefined;
    
    // name is undefined, but it doesn't blow up.
    const { name: name1 } = calledObject?.person ?? {};
    
    console.log(`name 1: ${name1}`); // name 1: undefined
    
    // ----------------
    
    // now it's an object, but doesn't have a person property
    calledObject = {};
    
    // name is still undefined, still doesn't blow up.
    const { name: name2 } = calledObject?.person ?? {};
    
    console.log(`name 2: ${name2}`); // name 1: undefined
    
    // ----------------
    
    // with person.name present…
    calledObject.person = { name: 'joe' };
    
    const { name: name3 } = calledObject?.person ?? {};
    
    // …it works as you'd expect
    console.log(`name 3: ${name3}`); // name 3: 'joe'