Reputation: 101
I have a homepage with multiple sections, and I wanted each section to get different data, one for "Popular Recipes" and one for "New Recipes" for example. So I wrote a switch statement inside a useeffect for this but it feels not "the best way" to me.
Home.js:
import React from "react";
import { Container } from "@chakra-ui/react";
import Section from "./Section";
const sections = [
{
name: "Popular Recipes",
},
{ name: "New Recipes" },
];
function Home() {
return (
<Container maxWidth="full">
{sections.map((section, i) => (
<Section key={i} name={section.name} />
))}
</Container>
);
}
export default Home;
Section.js:
import React, { useEffect, useState } from "react";
import { Text, Flex, Box, Spacer, SimpleGrid, Heading } from "@chakra-ui/react";
import { getAllRecipes } from "../api";
import Recipe from "../common/Recipe";
function Section(props) {
const [recipes, setRecipes] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
switch (props.name) {
case "Popular Recipes":
getAllRecipes()
.then((data) => {
setRecipes(data);
})
.catch((error) => setError(error.response.data.error));
}
}, []);
return (
<Box marginBottom="10">
<Heading as="h2" marginBottom="5" fontSize="xl" fontWeight="hairline">
{props.name}
</Heading>
<SimpleGrid minChildWidth="250px" columns={3} spacing={6}>
{error ? (
<Text>{error}</Text>
) : (
recipes?.map((recipe) => {
return <Recipe key={recipe._id} recipe={recipe} />;
})
)}
</SimpleGrid>
</Box>
);
}
export default Section;
Upvotes: 0
Views: 117
Reputation: 2653
Instead of depending on props.name
, just have your Section
component accept a getRecipes
prop and pass it explicitly in the parent component. This decouples name
from the actual implementation, so changing from Latest Recipes
to Latest Posts
(or whatever) won't break your app.
// queries.js -----
export const getPopularRecipes = () => fetch('/recipes/popular').then(res => res.json());
export const getLatestRecipes = () => fetch('/recipes/latest').then(res => res.json());
// Section.js -----
function Section(props) {
// ...
useEffect(() => {
props.getRecipes()
.then(data => setRecipes(data))
.catch(error => setError(error.response.data.error));
}, []);
// ...
}
// Home.js -----
import { getPopularRecipes, getLatestRecipes } from './queries';
function Home() {
return (
<Container maxWidth="full">
<Section name="Popular" getRecipes={getPopularRecipes} />
<Section name="Latest" getRecipes={getLatestRecipes} />
</Container>
);
}
Alternatively, if the logic for fetching recipes is identical (only the API path is different, for example), you can have the Section
component accept a recipeType
prop (or similar).
// Section.js -----
function Section(props) {
// ...
useEffect(() => {
fetch(`/recipes/${props.recipeType}`)
.then(res => res.json())
.then(data => setRecipes(data))
.catch(error => setError(error.response.data.error));
}, []);
// ...
}
// Home.js -----
import { getPopularRecipes, getLatestRecipes } from './queries';
function Home() {
return (
<Container maxWidth="full">
<Section name="Popular Recipes" recipePath="popular" />
<Section name="Latest Recipes" recipePath="latest" />
</Container>
);
}
Either way, decouple your network implementation from your name
and you should be resilient to future refactors.
Upvotes: 1