简体   繁体   中英

React-Redux: mapping an array of objects and initializing a component from each

I have a presentational component, , which takes a {props} object and populates itself with the proper values.

I also have a container component, , which is supposed to map state to props, take the array of objects representing the plots, map it and initialize a from each one.

This is throwing me an error- Uncaught (in promise) TypeError: Cannot read property 'name' of undefined . The "name" in question is a property of the plot.

Looking at the documentation, this error typically happens when we import a component with curly braces when we should import it without, but that's not the case here.

I have a feeling that what is going on is that I am improperly passing the props to the element, but am not sure of the right way to do it.

Plot.js:

import React from 'react';

const Plot = ({ props }) => {
    return (
        <div className="media col-md-4">
            <div className="media-left">
                <a href="#">
                    <img className="media-object" src="http://placehold.it/200/550" alt="Placehold" />
                </a>
            </div>
            <div className="media-body">
                <h4 className="media-heading">{props.name}</h4>
                <ul>
                    <li><strong>Grower: </strong> {props.grower}</li>
                    <li><strong>Region: </strong> {props.region}</li>
                    <li><strong>Current State: </strong> {props.currentState}</li>
                    <li><strong>Next State: </strong> {props.nextState}</li>
                    <li><strong>Days To Next State: </strong> {props.daysToNext}</li>
                    <br />
                    <span class="pull-right">
                        <i id="like1" class="glyphicon glyphicon-thumbs-up"></i> <div id="like1-bs3"></div>
                        <i id="dislike1" class="glyphicon glyphicon-thumbs-down"></i> <div id="dislike1-bs3"></div>
                    </span>
                </ul>
            </div>
        </div>
    );
};

export default Plot;

Dashboard.js:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
import Plot from './plot';

class Dashboard extends Component {
    componentWillMount() {
        this.props.fetchMessage();
        this.props.fetchPlots();
    }

    render() {
        const plots = this.props.plots;
        return (
            <div>
                <span>{this.props.message}</span>
                <div className='container'>
                        <div className="row">
                            {plots && plots.map((plot) => <Plot key={plot._id} name={plot.name} grower={plot.grower} region={plot.region} currentState={plot.currentState} nextState={plot.nextState} daysToNext={plot.daysToNext}/>)}
                        </div>
                </div>
            </div>
        );
    }
}

function mapStateToProps(state) {
    return {
        message: state.auth.message,
        plots: state.auth.plots
    }
}

export default connect(mapStateToProps, actions)(Dashboard);

EDIT:

This is fetchPlots(). I know that it's working and that plots are available as props, because when I add a console.(log) statement before the return statement in dashboard.js, I can see them, and they're fine, with all necessary properties.

export function fetchPlots() {
    return function (dispatch) {
        axios.get(`${ROOT_URL}/plots`, {
            headers: {
                authorization: localStorage.getItem('token')
            }
        })
            .then(response => {
                dispatch({
                    type: FETCH_PLOTS,
                    payload: response.data
                });
            });
    }
}

My reducer:

import {AUTH_USER, UNAUTH_USER, AUTH_ERROR, FETCH_MESSAGE, FETCH_PLOTS} from '../actions/types';

export default function(state={}, action){
    switch(action.type){
        case AUTH_USER:
            return{...state, error:'',authenticated:true};
        case UNAUTH_USER:
            return{...state, authenticated:false};
        case AUTH_ERROR:
            return { ...state, error: action.payload };
        case FETCH_MESSAGE:
            return { ...state, message: action.payload }
        case FETCH_PLOTS:
            return { ...state, plots: action.payload }
    }
    return state;

const Plot = ({ props })更改为const Plot = (props)

You are making an ajax call to get the data. So the ajax call takes some time to execute. Because of which this.props.plots would be undefined. So you need to make a null check in your Dashboard component

render() {
    const plots = this.props.plots;
    if(plots === undefined){
        return <div>Loading ...</div>
    }
    return (
        <div>
            <span>{this.props.message}</span>
            <div className='container'>
                    <div className="row">
                        {plots && plots.map((plot) => <Plot key={plot._id} name={plot.name} grower={plot.grower} region={plot.region} currentState={plot.currentState} nextState={plot.nextState} daysToNext={plot.daysToNext}/>)}
                    </div>
            </div>
        </div>
    );
}

Once the ajax call is finished the render function will be called again then the else condition will be followed and then it will not give the error you are getting.

Also make your api calls from componentDidMount() so that it's not called every time the state changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM