开发者问题收集

TypeError:无法读取未定义的属性“map”并四处走走

2020-04-03
68

有一个如下所示定义的对象 contactBook。我将其发送到 redux 并以完全相同的格式返回。

{“Book1” : [{name: “Bob”},{name, “Jane”}, {name, “Mary”]}

我打算将其转移到名称列表

import React, {Component} from 'react'
import {bindActionCreators} from "redux";
import * as actions from "../redux/actions";
import {withRouter} from 'react-router'
import {connect} from 'react-redux'

class ListContactComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            message: null
        };
    }

    componentDidMount() {
        this.props.startLoadingContacts(this.props.match.params.bookName);
    }


    addContactClicked = () => {
        this.props.history.push({
            pathname: `/addressBook/contact/`,
            state: this.state.bookName
        })
    };

    render() {
        let contacts = Object.values(this.props.contacts).flat();
        return (
            <div className="container">
                <h3>All Contacts</h3>
                {this.state.message && <div class="alert alert-success">{this.state.message}</div>}
                <div className="container">
                    <table className="table">
                        <thead>
                        <tr>
                            <th>Name</th>
                            <th>Phone Number</th>
                        </tr>
                        </thead>
                        <tbody>
                        {
                            contacts.map(
                                (contact, index) =>
                                        <tr key={index}>
                                            <td>{contact.name}</td>
                                            <td>{contact.phoneNumber}</td>
                                        </tr>
                                )
                        }
                        </tbody>
                    </table>

                    <div className="row">
                        <button className="btn btn-success" onClick={this.addContactClicked}>Add</button>
                    </div>
                </div>
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        contacts: state.contacts
    }
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators(actions, dispatch)
}

const connectedContactList = withRouter(connect(mapStateToProps, mapDispatchToProps)(ListContactComponent));
export {connectedContactList as ListContactComponent};
  1. 如果我使用:

    contacts = contactsBook[Book1]

我收到 TypeError:无法读取未定义的属性“map”

此错误的原因是什么,如何修复?

如果我不使用 redux 返回的对象,它就可以正常工作。我真的不知道有什么区别?

Actions:

export function startLoadingContacts(addressBookName) {
    return (dispatch) => {
        return AddressBookDataService
            .retrieveContacts(addressBookName)
            .then(
                (response) => {
                    let contacts = {};
                    contacts[addressBookName] = response.data;
                    dispatch(loadContacts(contacts))
                }).catch((error) => {
                console.log(error)
            })
    }
}

export function loadContacts(contacts) {
    return {
        type: 'LOAD_CONTACTS',
        contacts
    }
}

Reducer:

function contacts(state = {}, action) {
    switch (action.type) {
        case 'ADD_CONTACT':
            return "....";
        case 'LOAD_CONTACTS':
            return action.contacts;
        default:
            return state
    }
}
  • 控制台日志:

     contactsBook:
    
    {Book1: Array(3)}
    
    Book1: Array(3)
    
    0: {name: "Bob"}
    
    1: {name: "Jane"}
    
    2: {name: "Mary"}
    
    length: 3
    
    __proto__: Array(0)
    
    __proto__: Object
    
    contacts:
    
    (3) [{…}, {…}, {…}]
    
    0: {name: "Bob"}
    
    1: {name: "Jane"}
    
    2:{name:"Mary"}
    
    长度:3
    

    1. 如果我使用: contacts = Object.values(contactsBook) , 则没有输出。

    控制台日志:

     [Array(3)]
    
    0:Array(3)
    
    0:{name:"Bob"}
    
    1:{name:"Jane"}
    
    2:{name:"Mary"}
    
    长度:3
    
    __proto__:Array(0)
    
    长度:1
    

使用 JSON.stringy(contacts) 时

它会打印:

[[ {name:"Bob"},..]] 而不是[{name: "Bob"},.. ]

这种情况下,如何去掉外面的 []?

如果模拟一个数据扭曲器 =[[data]],我可以通过扭曲器[0]去除外层。

但是它不适用于

contacts = Object.values(contactsBook) contacts[0]

最后 flat() 解决了这个问题

contacts = Object.values(contactsBook).flat()

你能帮忙解释一下原因吗?

2个回答

如果我不得不猜测,您需要向 Reducer 添加初始状态,该状态不是空对象,例如空数组 [] 。这样,当组件首次呈现并连接到 redux 时,它将具有一个有效的定义值,可以进行映射。

编辑

好的,您的状态形状 {[book: string]: string[]> 。在这种情况下,Reducer 的初始状态 ( { ) 没问题 ,您 确实 需要从路由参数中获取图书名称。在这里,我更新了 mapStateToProps 函数,以便同时引入组件自己的 props,并进行计算以将 contactList 作为 prop 返回给组件。

/edit

Reducer

const initialState = {};

function contacts(state = initialState, action) {
    switch (action.type) {
        case 'ADD_CONTACT':
            return "....";
        case 'LOAD_CONTACTS':
            return action.contacts;
        default:
            return state
    }
}

Component

const { contactList } = this.props;

...

contactList.map(...

...

function mapStateToProps(state, ownProps) {
  const { match: { params: { bookName } } = ownProps;
  return {
    contactList: state.contacts[bookName] || [],
  }
}

替代解决方案 Guard Pattern

{
  contacts && contacts.map(
    (contact, index) => (
       <tr key={index}>
         <td>{contact.name}</td>
         <td>{contact.phoneNumber}</td>
       </tr>
  ))
}
Drew Reese
2020-04-03

将你的 map 函数更改为:

{contacts["Book1"].map((contact, index) => (
          <tr key={index}>
            <td>{contact.name}</td>
            <td>{contact.phoneNumber}</td>
          </tr>
))}

代码沙盒: https://codesandbox.io/s/react-example-pevdn

joy08
2020-04-03