Home > Enterprise >  How do you setState to empty when components that rely on this data throw errors without a placehold
How do you setState to empty when components that rely on this data throw errors without a placehold

Time:11-28

Problem Overview :

  1. Building personal website with a Homepage.js, a Sidebar.js component, and a Project.js component.
  2. Project components are mapped on Homepage from a project list array of objects.
  3. Sidebar.js component will open and display active project info when a Project component is clicked on.
  4. App.js has activeProject state, with a default set to first project in list so sidebar doesn't throw errors.
  5. End result is that Sidebar displays correct project title, info, and video src (inspect mode) on Project click, but the video itself is wrong and always shows the placeholder's video set on App.js

Props passes right info, wrong video

Details :

In my App.js I set activeProject to the first project in my list as a default, via it's title.

const [activeProject, setActiveProject] = useState(ListOfProjects[0].title);


  return (
    <div className="App">
      <Navigation />
      <HomePage 
        isOpen={isOpen}
        setIsOpen={setIsOpen}
        activeProject={activeProject}
        setActiveProject={setActiveProject}
      />
      <Sidebar
        isOpen={isOpen}
        setIsOpen={setIsOpen}
        activeProject={activeProject}
      />
      <Footer />
    </div>
  );

My projects are mapped out on my Homepage.js

<div className="project-list">
        {ListOfProjects.map((obj) => (
               <ProjectItem
                      key={obj.id}
                      title={obj.title}
                      video={obj.video}
                      videoAlt={obj.videoAlt}
                      liveLink={obj.liveLink}
                      codeLink={obj.codeLink}
                      isOpen={isOpen}
                      setIsOpen={setIsOpen}
                      activeProject={activeProject}
                      setActiveProject={setActiveProject}
               />
        ))}
</div>

Each project component has a click event to open the sidebar component with extra project information based on the project title that was clicked on.

const showSidebar = () => {
        setActiveProject(title);
        setIsOpen(!isOpen);
}

On Sidebar.js I have this list of props being pulled from the project with a title that matches the current active project set state.

const {title, liveLink, codeLink, video, videoAlt, tags, details, challenges, lessons} = ListOfProjects.find((project) => {
        return project.title === activeProject;
});

The result is that the sidebar component displays the correct title, project info, and even the right video src when shown in the inspection tool, but the project video is always of the first project in the list. Here is my website for more context (https://bryanfink.dev)

Things I have tried :

I tried changing the App.js activeProject state placeholder to the second project.

const [activeProject, setActiveProject] = useState(ListOfProjects[1].title);

This resulted in the Sidebar showing the correct project title, info, and video src(inspect mode) but now the video always shows the second project's video.

Then I tried changing the App.js activeProject state placeholder to ""

const [activeProject, setActiveProject] = useState("");

But this results in errors in the sidebar.

Sidebar.js:15 Uncaught TypeError: Cannot destructure property 'title' of '_Projects_listOfProjects__WEBPACK_IMPORTED_MODULE_2__.default.find(...)' as it is undefined

CodePudding user response:

Try this, the find may return undefined if it can not find the data. So you can not destruct undefined. Adding || {} will check if ListOfProjects.find((project) => { return project.title === activeProject; }) is undefined, it will change to an empty object {}

const {title, liveLink, codeLink, video, videoAlt, tags, details, challenges, lessons} = ListOfProjects.find((project) => {
        return project.title === activeProject;
}) || {};

CodePudding user response:

Simply, create a default project

const defaultProject = {
title: "",
liveLink: "",
}
const {title, liveLink, codeLink, video, videoAlt, tags, details, challenges, lessons} = ListOfProjects.find((project) => {
        return project.title === activeProject;
}) || defaultProject;

Also, make sure the title is unique or the .find will be returning wrong project.

CodePudding user response:

I guess the issue is not the way you pass the data to your component. The issue is, when you rerender your component, it changes the src in your video <source /> tag but it does not actually reload the video, thus you see an old or wrong video even with the correct URL. I would suggest load() the video with each call to your child component that shows the video. For example call load in useEffect whenever the video source changed:

useEffect(() => {
    document.querySelector("video").load();
}, [])

This will force the video to reload with the new src.

  • Related