Search code examples
reactjsfetch

React 18 Rendering Before setState causing error


So I've been trying to make super simple api request like the following and store it into a useState var, however after the recent update to React 18, I get an error before anything can render because str returns as undefined. It is not a failure to return data from the api but str returning as undefined because it is not waiting for the state of data to be set.

I am not sure of what to do because in previous versions of React, I have not had this problem. Has anyone figured out what could possible be the issue? I checked the docs but there doesn't seem to be any mention of this being something to be aware of.

const Component = () => {

      const [data, setData] = useState(null);
      const str = data.data.sentence

          useEffect(() => {
            fetch("https://api.hatchways.io/assessment/sentences/2")
              .then((res) => res.json())
              .then((data) => setData(data));
          }, []);
       
       return (
         <div> 
            <p>{str}</p>
         </div> 
    )
}

Solution

  • Because data.data.sentence is undefined when you declare it as str the whole component will throw an error. So you need to set it as it could be null.

    const str = data?.data.sentence
    

    This has always been the case with older versions of React so you were probably doing something else.

    I personally would have a loading state in there so you wouldn't render str without there being a value.

    const Component = () => {
    
          const [data, setData] = useState(null);
          const str = data.data.sentence
    
              useEffect(() => {
                fetch("https://api.hatchways.io/assessment/sentences/2")
                  .then((res) => res.json())
                  .then((data) => setData(data));
              }, []);
    
           if(!str){
              return 'loading'
           }
           
           return (
             <div> 
                <p>{str}</p>
             </div> 
        )
    }