0

I have this library type application that lists every object owned by a users. Users can select an object and open up a page about the details for that object alone (Or enter its specific URL using a slug). Both components are siblings.

Currently with my set-up, I keep pinging the server for data that is already loaded up in my parent component.

How can I pass an ID of my buckets props to the child component to then only display data pertaining to that JSON object?

Library List:

In this comp, I'm mapping out all user objects known as buckets

const UserBuckets = (props) => {
    const { buckets } = props;
    const classes = useStyles();
    if (!buckets || buckets.length === 0) return <p>Can not find any buckets, make one below!</p>;

    return (
        <React.Fragment>
            <Container maxWidth="md" component="main">
                <Grid container spacing={5} alignItems="flex-end">
                    {buckets.map((buckets) => {
                        return (
                            // Enterprise card is full width at sm breakpoint
                            <Grid item key={buckets.id} xs={12} md={4}>
                                <Card className={classes.card}>
                                <CardHeader className={classes.bucketTitle} classes={{ title: classes.bucketTitle }}
                                    title = {buckets.name.substr(0, 50)}
                                    subheader = {"Total Stocks " + buckets.stock_count}
                                    action={
                                    <IconButton aria-label="settings">
                                        <MoreVertIcon />
                                    </IconButton>
                                    }
                                />
                                    <Link 
                                        color="textPrimary"
                                        href={'dash/' + buckets.slug}
                                        className={classes.link}
                                    >                                   
                                    <CardContent className={classes.cardContent}>
                                        <div className={classes.bucketText}>
                                            <Typography
                                                component="p"
                                                color="textPrimary"
                                            ></Typography>
                                            <Typography variant="subtitle1" color="textSecondary">
                                                {buckets.stock_list}...
                                            </Typography>                                           
                                        </div>              
                                    </CardContent>
                                    </Link>
                                </Card>
                            </Grid>
                        );
                    })}
                </Grid>
            </Container>
        </React.Fragment>
    );
};
export default UserBuckets;

Specific object from library list:

For this comp, I'm display data for only one bucket. If there is no state management already loaded for specific bucket object, then the UseEffect will still be in play here (correct me if I'm wrong please).


export default function Bucket() {
    const { slug } = useParams();
    const classes = useStyles();

    const [data, setData] = useState({ bucket: [] });

    useEffect(() => {
        axiosInstance.get('bucket/' + slug + '/').then((res) => {
            setData({ bucket: res.data });
            console.log(res.data);
        });
    }, [setData, slug]);

    return (
        <Container component="main" maxWidth="md">
            <CssBaseline />
            <div className={classes.paper}></div>
            <div className={classes.heroContent}>
                <Container maxWidth="sm">
                    <Typography
                        component="h1"
                        variant="h2"
                        align="center"
                        color="textPrimary"
                        gutterBottom
                        className = {classes.bucketTitle}
                    >
                        {data.bucket.name}
                    </Typography>
                    <Typography
                        variant="h5"
                        align="center"
                        color="textSecondary"
                        paragraph
                        className = {classes.bucketAbout}
                    >
                        {data.bucket.about}
                    </Typography>
                    <SymbolInput/>
                </Container>
            </div>
            <div>< DataTables /></div>
        </Container>
    );
}

Which Hook or state management do I pass to the children pages, without having to load the JSON object again via the server? Thank you for helping me understand.

EDIT: Got confused with my terminology, here is the parent app that loads the data through GetUserBuckets().

function App()
{
    const user = useSelector(selectUser);

    return (
        <div>
            {user ? GetUserBuckets() : AppWelcome()}
        </div>
    );
}
export default App;

Here is the function that does the actual get call to my database.

export default function GetUserBuckets()
{
    const classes = useStyles();
    const ListLoading = LoadingComponent(UserBuckets);
    const [appState, setAppState] = useState({
        loading: true,
        posts: null,
    });


    useEffect(() =>
    {
        axiosInstance.get('all/buckets/').then((res) =>
        {
            const allBuckets = res.data;
            setAppState({ loading: false, buckets: allBuckets });
            console.log(res.data);
        });
    }, [setAppState]);

    return (
        <div className={classes.text}>
            <h1>Buckets</h1>
            <ListLoading isLoading={appState.loading} buckets={appState.buckets} />
            <Container className={classes.createBucket}>
                    <CreateDialog />    
            </Container>
        </div>
    );
};
andres
  • 1,558
  • 7
  • 24
  • 62
  • It sounds like you're showing either the bucket cards or a single bucket; to avoid loading the data again you need to move up loading the data to the parent of `UserBuckets` (App?), so you don't lose the data when `UserBuckets` gets unmounted. Next you render either the bucket cards or a single bucket depending on the URL, and pass all buckets as prop in the former case, and just the specific bucket in the latter case (using the slug id). –  Feb 09 '21 at 18:17
  • You can use contextAPI to save data and then use that in children or anywhere ! – Abu Sufian Feb 09 '21 at 18:17
  • @AbuSufian True, but only needed if you want to pass down props through multiple levels. Context is a convenience, not a necessity. –  Feb 09 '21 at 18:18
  • @ChrisG, I didn't show it but I have all the data already loaded in my App. I have the URL patterns down, everything is working fine. I'm really just trying to figure out how you go about doing what you say :"pass all buckets as prop, and render bucket via slug ID". Perhaps you can show me an example? – andres Feb 09 '21 at 18:22
  • ContextAPI could also be another option. – andres Feb 09 '21 at 18:23
  • 1
    You call the two components "parent" and "child", but it sounds like they're siblings? Anyway, what we actually need to see is the parent where you're loading all buckets, where you're rendering UserBuckets / Bucket. –  Feb 09 '21 at 18:25
  • Chris, thank you for the correction. React terminology is still new to me. I have edited the original post to show the parent app. – andres Feb 09 '21 at 18:30
  • I see, so where are you checking the URL? A card has a `href={'dash/' + buckets.slug}` link for each bucket, but I'm not seeing any code that checks the current URL. The basic idea is to have `` in your main JSX. –  Feb 09 '21 at 18:32
  • I'm using react-router-dom, `` – andres Feb 09 '21 at 18:35
  • Right, all pretty pertinent information... :) We can finally solve this, since you're using react-router: ` } />`. Inside the bucket component you can now use `props.buckets[props.match.params.slug]` –  Feb 09 '21 at 18:38
  • 1
    You're using functional components, so all you need is right here: https://reactrouter.com/web/example/url-params –  Feb 09 '21 at 18:41
  • Okay now I understand :), how would I be able to pass my appState to my index? – andres Feb 09 '21 at 18:46
  • Which index do you mean? Do you mean `App`? –  Feb 09 '21 at 18:48
  • Sorry I should of been more clear, I store all of my paths react-dom inside my `index.js` file. – andres Feb 09 '21 at 18:51
  • 1
    For any given state that is needed in multiple components, put it in the one highest up the tree. You're using Redux though, which might have other ways of doing that. This is also a separate question which I'm sure also has many existing solutions. –  Feb 09 '21 at 18:54
  • Okay thank you very much for the help, feel free to add an answer to this question so I can mark this post solved :) – andres Feb 09 '21 at 18:55
  • 1
    As far as I can tell, this question is primarily about passing the bucket data to a route component; you had getting the bucket slug down, so what was left is basically answered here: https://stackoverflow.com/questions/44255415/passing-custom-props-to-router-component-in-react-router-v4 –  Feb 09 '21 at 19:05

0 Answers0