How to set initial state value in Gatsby based on the result from static query?

Viewed 172

I'm trying to make a video filtering UI. It will have a grid of videos and some filters in the sidebar. My videos are an array of items/objects that I get from a Gatsby static query.

One of my filters (from a material-ui Autocomplete component) generates an an array of tags, e.g ["data science", "javascript"]. I'm trying to filter the videos list down according to whether the tags in the filters match any of the video tags.

I'm not sure how to make this gatsby component stateful in the way I want to.

  • I want to be able to give my VideosGrid component all of the videos on initial load (as there are no filters set)

  • I have the multichip component able to call setFilterTags

  • I'm try to use useEffect to listen for changes on the filterTags and then trigger a state change and update the videos that get passed to the videos grid component.

  • But I can't figure out how to make the gatsby data stateful. When I tried, const [filteredItems, setfilteredItems] = useState([data.allItem.edges]); it breaks because my video grid component doesn't have anything to load.

export default function LandingPage() {
  const classes = useStyles();

  const data = useStaticQuery(graphql`
    query MainIndexQuery {
      allItem(sort: {fields: view_count, order: DESC}) {
        edges {
          node {
            title
            tags
            stuff
          }
        }
      }
    }
  `);

  const [filterTags, setFilterTags] = useState([]);

  const [filteredItems, setfilteredItems] = useState([data.allItem.edges]);
  // ```this doesn't seem to work.```;

  //  let filteredItems = data.allItem.edges; // this works

  useEffect(() => {
    filteredItems = filteredItems.filter(function (el) {
      return el.node.tags.some((tag) => filterTags.includes(tag));
    });
    // I want to call setState here
  }, [filterTags]);

  // setFilterTags gets invoked by my chip filtering UI component...

  return (
    <>
      <MultiChip setFilterTags={setFilterTags} />

      <VideosGrid locations={filteredItems} />
    </>
  );
}
1 Answers

I think you want to use:

  const [filteredItems, setfilteredItems] = useState(data.allItem.edges);

The edges (from data.allItem.edges) is an array of images itself so you don't need to wrap it.

In addition, to avoid mutation caveats, I will suggest cloning the state array of data. Something like this will create a shallow clone:

  useEffect(() => {
    let clonedArray= [...filteredItems];
    filteredItems = clonedArray.filter(function (el) {
      return el.node.tags.some((tag) => filterTags.includes(tag));
    });
    // I want to call setState here
  }, [filterTags]);
Related