0

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?

2
  • Can you insert console.log(props) to generate to check the content of your props and report back? Commented Mar 30, 2020 at 16:07
  • I notice that the console is called twice. The first time it's an empty array, while there are values in the second call. By logging only props the result remains the same except that it has a nested dict over it (data) Commented Mar 30, 2020 at 16:22

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

0

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: [] }
    }
// ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.