0

I am trying to pass the petData via context to the SearchPage component. The petData is returning undefined. Any help in what I am doing wrong.

Thanks

Context.js

import { createContext } from "react";

const PetDataContext = createContext();

export default PetDataContext;

App.js

On the app.js I am fetching data and putting it into a state accessible outside the scope of the axios request. I am then trying to pass it via the useContext hook.

import PetDataContext from "./Context/context";


function App() {
  const [petData, setPetData] = useState();
  useEffect(() => {
    axios
      .get(`${BACK_PORT}/data`)
      .then(function (response) {
        setPetData(response.data);
      })
  }, []);
  console.log(petData);

  return (
    <div className="App">
      <PetDataContext.Provider value={{ petData }}>
        <BrowserRouter>
          <NavBar />
          <Switch>
            <Route path="/" component={MainSignedOut} exact />
            <Route path="/mainsignedin" component={MainSignedIn} />
            <Route path="/searchpage" component={SearchPage} />
            <Route path="/mypets" component={MyPets} />
            <Route path="/admin" component={Admin} />
            <Route exact path="/pets/:id" component={PetPage} />
            <Route component={err404} />
          </Switch>
        </BrowserRouter>
      </PetDataContext.Provider>
    </div>
  );
}

export default App;

SearchPage.jsx

On the SearchPage component I am trying to pass the petsData via useContext, however it is returning undefined.

import PetDataContext from "../../Context/context";


function SearchPage() {
  const { petData } = useContext(PetDataContext);
  console.log("testing123", petData); //returns undefined

  const [filter, setFilter] = React.useState("");

  const filteredData = React.useMemo(() => {
    if (filter == "") return petData;
    return petData.filter(
      (item) =>
        item.name.toLowerCase().includes(filter) ||
        item.breed.toLowerCase().includes(filter)
    );
  }, [petData, filter]);

  return (
    <>
      <SearchBar onSearch={(searchTerm) => setFilter(searchTerm)} />
      <div className="d-flex flex-wrap sp-body">
        <DogCardsDisplayed petData={filteredData} />
      </div>
    </>
  );
}

export default SearchPage;
Tim Keating
  • 6,443
  • 4
  • 47
  • 53
coolps811
  • 193
  • 4
  • 11

1 Answers1

2

You've set up your initial value to be undefined with this line of code:

const [petData, setPetData] = useState();

If that's not what you want for the initial value, then put something else there such as an empty array.

const [petData, setPetData] = useState([])

Alternatively, you can keep it as undefined and check for that value to be a possibility where you consume it.

  const filteredData = React.useMemo(() => {
    if (!petData) return []; //<--- added this
    if (filter == "") return petData;
    return petData.filter(
      (item) =>
        item.name.toLowerCase().includes(filter) ||
        item.breed.toLowerCase().includes(filter)
    );
  }, [petData, filter]);

P.S: Not related to your bug, but the following may cause performance issues that don't need to be there:

value={{ petData }}

Every time App renders, this is going to create a new object. The petData may be the same, but the object around it is new. As a result, all consumers are forced to rerender too even if nothing changed.

If this is the only piece of data you need to provide, then you can just remove the object and provide the array directly:

value={petData}

// And change how you consume it to:
const petData = useContext(PetDataContext);

If you need an object because you'll be providing multiple things, then memoize the object so it only gets recreated when its data changes:

const value = React.useMemo(() => {
  return { petData, somethingElse }
}, [petData, somethingElse]);

// ...

 <PetDataContext.Provider value={value}>
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98