Search Input React JS

I’m building an app with react using the hacker news API. I’m trying to search my stories by title, but I can’t seem to make it work. Is there a way to access all Story component as if it was an array so I can filter?

Working version HERE

I know how to handle the search event getting the value from the input and using that to filter an array. the problem is that I’m not sure how to access the stories array that is rendered on the screen already

Sorry if something doesn’t make sense, I’m still learning and a bit confused.

// APICALLs file 

// Return a promise with all new stories IDs
export const getStoryIds = async (url) => {
  const response = await axios.get(url).then((data) => data);

  return response.data;
};

// Return a promise with a story item
export const getStory = async (storyId) => {
  const response = await axios
    .get(`${storyUrl + storyId}.json`)
    .then((data) => data);

  return response.data;
};


//Main container where I render all stories

import { Fragment, useEffect, useState } from "react";
import { GlobalStyle } from "../styles/GlobalStyles";
import {
  getStoryIds,
  newStoriesUrl,
  bestStoriesUrl,
  showStoriesUrl,
  jobStoriesUrl,
} from "../services/Api";
import { Story } from "./Story";
import { useInfiniteScroll } from "../hooks/useInfiniteScroll";
import {
  StoriesContainerStyle,
  ContainerTitle,
} from "../styles/StoriesContainer";
import { ButtonContainerStyle } from "../styles/ButtonContainer";
import { ButtonStyle } from "../styles/ButtonStyle";

export const StoriesContainer = () => {
  const count = useInfiniteScroll();
  const [storyIds, setStoryIds] = useState([]);
  const [filter, setFilter] = useState([]);

  const handleClick = (url) => (event) => {
    getStoryIds(url).then((data) => setStoryIds(data));
  };

  useEffect(() => {
    getStoryIds(newStoriesUrl).then((data) => setStoryIds(data));
  }, []);


  return (
    <Fragment>
      <GlobalStyle />
      <StoriesContainerStyle>
        <ContainerTitle>Hacker News</ContainerTitle>
        <ButtonContainerStyle>
          <ButtonStyle onClick={handleClick(newStoriesUrl)}>New</ButtonStyle>
          <ButtonStyle onClick={handleClick(bestStoriesUrl)}>Best</ButtonStyle>
          <ButtonStyle onClick={handleClick(showStoriesUrl)}>Show</ButtonStyle>
          <ButtonStyle onClick={handleClick(jobStoriesUrl)}>Jobs</ButtonStyle>
        </ButtonContainerStyle>
        {storyIds.slice(0, count).map((storyId) => (
          <Story key={storyId} storyId={storyId} />
        ))}
      </StoriesContainerStyle>
    </Fragment>
  );
};

//Story Component

import { useState, useEffect, memo } from "react";
import { getStory } from "../services/Api";
import { StoryCard, StoryDetail, StoryTitle } from "../styles/StoryStyle";
import { formatTime } from "../utils/formatTime";

export const Story = memo(function Story({ storyId }) {
  const [story, setStory] = useState([]);

  useEffect(() => {
    getStory(storyId).then((data) => setStory(data));
  }, []);

  return story && story.url ? (
    <StoryCard href={story.url} target="_blank" rel="noreferrer">
      <StoryTitle>{story.title}</StoryTitle>
      <StoryDetail>
        By: {story.by} | Posted: {formatTime(story.time)}
      </StoryDetail>
    </StoryCard>
  ) : null;
});

Answer

https://codesandbox.io/embed/react-hooks-search-filter-4gnwc

My code from work (looks very similar as in the link):

   useEffect (() => {
        dispatch(retrieveDevices())
        // eslint-disable-next-line
    }, []);

    useEffect(() => {
        const results = devices.filter(device => device.deviceId.toString().toLowerCase().includes(searchTitle.toLowerCase()));
        setSearchResults(results);
    }, [devices, searchTitle]);

My original code which caused infinite loop of SQL queries (GET request over and over and over…):

    useEffect(() => {
        const results = devices.filter(device => device.deviceId.toString().toLowerCase().includes(searchTitle.toLowerCase()));
        setSearchResults(results);
        if (!searchTitle) {
          dispatch(retrieveDevices())
}
    }, [dispatch, searchTitle, devices]);

With the addition that, if your variable is String, you probably need to add ‘toString().’ (EDIT) BEFORE the first ‘toLowerCase().’ or else it won’t properly pass the format.

Also, from that link, the list code is somewhat close to mine:

{filteredCountries.map((country, idx) => (
        <CountryDetail key={idx} {...country} />
      ))}

But from my former repository before today’s work and with just one word edited different than prior version, here’s how I rendered my list properly and works exactly as that example does (EDIT: This stays the same):

{devices &&
     searchResults.map((device, index) =>

EDIT: Got my code and replaced code samples and even revised, as I had created an infinite loop for myself (whoops)