user8817894
user8817894

Reputation:

Render objects in a List in React

I want to retrieve a list of Companies on a page. I consoled the incoming data just to be sure and it looks as follows

  "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": "56407787-472f-44c9-b726-189798c7e217",
            "address": {
                "street": "test street",
                "postcode": "test 12",
                "city": "test city",
                "country": "test country"
            },
            "contact_name": "Angy",
            "contact_phone": "33333333",
            "contact_email": "[email protected]",
        }

The following component creates a list

import React from 'react';

import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import IconButton from '@material-ui/core/IconButton';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import EditIcon from '@material-ui/icons/Edit';

const useStyles = makeStyles((theme) => ({
    root: {
        flexGrow: 1,
        maxWidth: 752,
    },
    demo: {
        backgroundColor: theme.palette.background.paper,
    },
    title: {
        margin: theme.spacing(4, 0, 2),
    },
}));

function generate(props) {
    return props.data.results.map((com) =>
        <ListItem key={com.id}>
            <ListItemText primary={com.name}/>
            <IconButton edge="end" aria-label="edit">
                <EditIcon />
            </IconButton>
        </ListItem>
    )}

const Company = (props) => {
    const classes = useStyles();

    // console.log('data is ', props.data.results)

    return (
        <div className={classes.root}>
            <Grid container spacing={2}>
                <Grid item xs={12} md={6}>
                    <Typography variant="h6" className={classes.title}>
                        company list
                    </Typography>
                    <div className={classes.demo}>
                        <List> {generate(props)} </List>
                    </div>
                </Grid>
            </Grid>
        </div>
);
};

export default Company;

The following component renders the list:

import React from "react";
import axios from 'axios';

import Company from "./Company";

class CompanyList extends React.Component {

    state = {
        companies: []
    }

    componentDidMount() {
        axios.get('http://127.0.0.1:8000/companies')
            .then(res => {
                this.setState({
                    companies: res.data
                    });
                console.log(res.data)
            })
    }

    render() {
        return (
            <Company data={this.state.companies}/>
        )
    }
}

export default CompanyList;

I receive an error as

TypeError: Cannot read property 'map' of undefined

I am new to ReactJS, and presumably stuck with this error. What am I doing wrong here?

Upvotes: 0

Views: 64

Answers (3)

kmui2
kmui2

Reputation: 2517

Like what you're seeing, it's initially an empty array on first render than a nested dict (aka object) in your second render, but you're handling like it'll just be a nested object.

I do not know what exactly you need (rendering an empty list, not rendering a list at all, passing an object/array, etc.). Here is simple fix you can do so props.data is always a defined nested object:

class CompanyList extends React.Component {

    state = {
        companies: { results: [] }
    }
// ...

Upvotes: 0

David
David

Reputation: 342

Your initial state has companies which is an empty array and your res.data is an object. Initially, there is no results in an empty array. Due to asynchronous call, you should check if results exists. This (props.data.results||[]) might solve your problem. Basically it says if there is results use it else use an empty array.

Upvotes: 1

Slim
Slim

Reputation: 683

You are not passing the state to the child that needs to use the companies data (so from the CompanyList component to your Company function https://reactjs.org/docs/state-and-lifecycle.html

Either use state management (Redux for instance) to link your Company props to the CompanyList state, or create a Context and combine with the useContext hook https://reactjs.org/docs/hooks-reference.html#usecontext

Upvotes: 0

Related Questions