Home > Net >  Conditional rendering with useEffect / useState, why is there a delay in the DOM when switching comp
Conditional rendering with useEffect / useState, why is there a delay in the DOM when switching comp

Time:07-14

Intro / Context

I am trying to build an application using React that allows for image or video display based on a chosen menu item. I am currently using Advanced Custom Fields within WordPress to build my data objects and using graphQL to query them into my project.

I want the application to display either a video component or an image component. This choice will be determined through conditional rendering and based on the contents of the object's fields.

Each object contains a title, an image field and a video field. If the entry in question should be displayed as an image the video field will be set as the string 'null'. All fields will return strings regardless.

I am using useState to target a particularly active field, however, despite triggering a change in state conditional rendering does not appear to change.

The Application

This is my approach

function Display({ objects }) {

  const [setVisualOption, changeVisualOption] = useState(false);

  const [appState, setState] = useState({
    myObjects: objects,
    activeTitle: "null",
    activeImage: "null",
    activeMediaUrl: "null",    
  });

 function toggleActive(index, trackIndex) {
    setState({
      ...appState,
      activeTitle: appState.myObjects[index].title,
      activeImage: appState.myObjects[index].image[0].mediaItemUrl,
      activeMediaUrl: appState.myObjects[index].mediastreamurl,
    });
    changeVisualOption(appState.activeImage.includes("null"));
  }

  useEffect(() => {}, [
    appState.activeTitle,
    appState.activeImage,
    appState.activeMediaUrl,
    setVisualOption,
  ]);

  return (
        <div className="display">
           <div className="list-box-right>
             {appState.myObjects.map((element, index) => (
                 <>
                   <div
                     key={index}
                     className="menu-item"
                     onClick={() => {
                     toggleActive(index);
                     }}
                    >
                    {element.title}
                </div>
             </>
             ))}
             </div>
               <div className="right-grid">
                {setVisualOption ? (
                  <VideoComponent activeImage={appState.activeImage}></VideoComponent>
                 ) : (
                  <ImageComponent activeImage={appState.activeImage}></SingleImage>
                 )}
              </div>
            </div>
          );
}

The summarise, to component takes objects as prop which are being passed down from another component making the graphQL query. I am then setting the initial values of useState as an object and setting an activeTitle, activeImage and activeMediaUrl as null.

I am then using a function to toggle the active items using the setState modifier based upon the index that is clicked within the return statement. From there I am using setVisualOption and evaluating whether the activeImage is contains 'null' (null.jpg), if this is true setVisualOption will be set to true allowing the Video Component to be rendered

The Problem

To be clear, there are no errors being produced and the problem is a slight rendering issue where it requires double clicks to alter the state and trigger the correct response from the tertiary operator.

The issue is within the conditional rendering. If I set my object fields to all images and return only the Image Component there are no issues, and the state change can be seen to register visually as you click down the listed options.

It is only when I introduce the conditional rendering that there is a delay, the first click does not generate the correct response from the component I am trying to display however the second click triggers the right response.

As you can see, I am also using useEffect to try and trigger a rendered response when any of the described states change but still encounter the same problem.

Does anyone know what is the cause of this bug? when looking at the console.log of setVisualOption is not appearing as true on first click when it aught to.

Any insights would be great thanks

CodePudding user response:

You set your visual option right after you set your appState, this is why appState.activeImage in changeVisualOption is not updated because state updates in React is asynchronous. You can either use useEffect to update visual option when the appState changes or you can use appState.myObjects[index].image[0].mediaItemUrl in changeVisualOption

function toggleActive(index, trackIndex) {
  setState({
    ...appState,
    activeTitle: appState.myObjects[index].title,
    activeImage: appState.myObjects[index].image[0].mediaItemUrl,
    activeMediaUrl: appState.myObjects[index].mediastreamurl,
  })
changeVisualOption(appState.myObjects[index].image[0].mediaItemUrl.includes("null"))
}

or

useEffect(() => {
  changeVisualOption(appState.activeImage.includes("null"))
}, [appState])
  • Related