【问题标题】:Map stops iterating after first iteration in ReactMap 在 React 中的第一次迭代后停止迭代
【发布时间】:2020-12-15 22:50:13
【问题描述】:

我的组件应该在组件挂载时检索课程数据。我遇到的问题是,无论我使用课程 ID 还是课程标题​​作为键,我都会收到以下错误:

index.js:1 警告:列表中的每个孩子都应该有一个唯一的“key”属性。

我查看了 Stack Overflow 上的 react 文档,并尝试了不同的方法来使其工作。我可以让它部分工作的唯一方法是添加一个索引作为地图的参数。当我使用这种方法时,我遇到了另一个问题,即它在第一次迭代后停止,即使有 10 个项目。我该如何解决这个问题?

这是我的代码:

CoursesPage.js

import React from 'react';
import { connect } from 'react-redux';
import * as courseActions from '../../redux/actions/courseActions';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';

class CoursesPage extends React.Component {

    componentDidMount() {
        this.props.actions.loadCourses().catch(error => {
            alert("Loading courses failed" + error);
        });

    }


    render() {
        return (
            <>
                <h2>Courses</h2>

                

{this.props.courses.map((course, index) => (

                    <div key={course[index].title}>{course[index].title}</div>


                ))}
            </>
        );
    }
}

CoursesPage.propTypes = {
    courses: PropTypes.array.isRequired,
    actions: PropTypes.object.isRequired
}

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

}

function mapDispatchToProps(dispatch) {

    return {
        actions: bindActionCreators(courseActions, dispatch)
    }

}

export default connect(mapStateToProps, mapDispatchToProps)(CoursesPage);

我的模拟数据:

const courses = [
    {
        id: 1,
        title: "Securing React Apps with Auth0",
        slug: "react-auth0-authentication-security",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 2,
        title: "React: The Big Picture",
        slug: "react-big-picture",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 3,
        title: "Creating Reusable React Components",
        slug: "react-creating-reusable-components",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 4,
        title: "Building a JavaScript Development Environment",
        slug: "javascript-development-environment",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 5,
        title: "Building Applications with React and Redux",
        slug: "react-redux-react-router-es6",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 6,
        title: "Building Applications in React and Flux",
        slug: "react-flux-building-applications",
        authorId: 1,
        category: "JavaScript"
    },
    {
        id: 7,
        title: "Clean Code: Writing Code for Humans",
        slug: "writing-clean-code-humans",
        authorId: 1,
        category: "Software Practices"
    },
    {
        id: 8,
        title: "Architecture Applications for the Real World",
        slug: "architecting-applications-dotnet",
        authorId: 1,
        category: "Software Architecture"
    },
    {
        id: 9,
        title: "Becoming an Outlier: Reprogramming the Developer Mind",
        slug: "career-reboot-for-developer-mind",
        authorId: 1,
        category: "Career"
    },
    {
        id: 10,
        title: "Web Component Fundamentals",
        slug: "web-components-shadow-dom",
        authorId: 1,
        category: "HTML5"
    }
];

const authors = [
    { id: 1, name: "Cory House" },
    { id: 2, name: "Scott Allen" },
    { id: 3, name: "Dan Wahlin" }
];

const newCourse = {
    id: null,
    title: "",
    authorId: null,
    category: ""
};

module.exports = {
    newCourse,
    courses,
    authors
};

编辑: 我正在使用 Redux Thunk。

这是我的 actionType.js 文件:

export const CREATE_COURSE = "CREATE_COURSE";
export const LOAD_COURSES_SUCCESS = "LOAD_COURSES_SUCCESS";

这是我的 CourseActions.js 文件:

import * as types from './actionTypes';
import * as courseApi from "../../api/courseApi";

export function createCourse(course) {
    return { type: types.CREATE_COURSE, course };
}

export function loadCourseSuccess(courses) {
    return { type: types.LOAD_COURSES_SUCCESS, courses };
}

export function loadCourses() {
    return function (dispatch) {
        return courseApi.getCourses().then(courses => {
            dispatch(loadCourseSuccess(courses));
        }).catch(error => {
            throw error;
        })

    }
}

这是我的 courseReducer.js 文件:

import * as types from '../actions/actionTypes';

export default function courseReducer(state = [], action) {

    switch (action.type) {
        case types.CREATE_COURSE:
            return [...state, { ...action.course }];

        case types.LOAD_COURSES_SUCCESS:
            return [...state, { ...action.courses }];

        default:
            return state;
    }
}

任何帮助将不胜感激。

谢谢。

附注我知道您应该使用 Id 作为密钥。但是现在必须这样做的方法是使用课程的标题作为关键字。

【问题讨论】:

  • 在地图内不需要访问 course[index]。 course 已经包含与当前索引有关的值。就做 course.title
  • 嗨,我遇到了我在帖子顶部提到的相同错误:index.js:1 Warning: Each child in a list should have a unique "key" prop.
  • 你不需要索引来迭代数组。仅当您在数组中映射数组并需要检查某些条件时才使用该方法。@MA_Dev 给出正确的分析器。试试你也放key={index}
  • 它很好。它只是输出到问题所在的页面。我在地图中有 console.log(course),它输出得很好。

标签: javascript reactjs redux ecmascript-6 redux-thunk


【解决方案1】:

通过您的修改,我认为我们可以更有效地帮助您。对于将来,发布您的代码示例将是有益的 https://codesandbox.io/

另外为了在调试时帮助自己,将 react 组件与 redux 的使用隔离开来。这将允许你确保你的 react 组件在给定数据时呈现,然后专注于让 redux 为你提供你的 react 组件所拥有的数据。

您可以通过首先在您的 React 组件中定义模拟数据,然后将该模拟数据移动到您的减速器,最后用实时 api 调用替换模拟数据来做到这一点。

进入代码:

您有两个问题:第一个是您想要索引到数组 courses,但由于拼写错误,您实际上是在使用属性访问器到对象 course

key={course[index].title}

正如您的问题所述,您必须使用标题作为键,只需将 div 更改为:

&lt;div key={course.title}&gt;{course.title}&lt;/div&gt; 并且您的代码应该可以按预期工作。

一旦您解决了这个问题,然后使用 Redux 从您的 API 调用中重新启用加载数据,您就可以解决 Redux 的问题。

查看您的减速器,您有一个明显的错误,并且根据您的用例,一个潜在的错误:

case types.LOAD_COURSES_SUCCESS:
            return [...state, { ...action.courses }];

action.courses 是一个数组,代码正在创建一个新数组,其中包含先前数组state 的所有元素,并添加一个新对象,该对象包含解构后的array.courses 数组的内容。

这实际上是将单个对象附加到您的数组中,并且该对象由您的课程数组中的元素组成。项索引成为键,项本身就是值。

您可以在此处对其进行可视化:https://codesandbox.io/s/divine-pond-nr3j8

你想要的

return [...state, ...action.courses];

第二个潜在的错误是,您实际上是在附加课程 api 的结果。对于后续调用加载课程,您将复制数据。这可能是你想要的,但我会假设这不是你想要的。

因此,您的 LOAD_COURSES_SUCCESS 案例应该被重写为:

return [...action.courses];

【讨论】:

  • 同样的错误:Warning: Each child in a list should have a unique "key" prop.
  • 嗨艾伦,感谢您的建议和帮助。正如您正确指出的那样,问题出在减速器中。当我尝试return [...action.courses]; 它工作时,控制台中没有出现错误并且页面上加载了课程。感谢所有帮助过我的人。感谢您的所有帮助。
【解决方案2】:

有很多方法可以在迭代时传递密钥...

var courses = this.state.courses.map(function(course, index) {
        return(
            <div key={index}>
                <div key={course.title} id={course.title}>
                    <h2 key={"header"+course.title}>{course.title}</h2>
                </div>
            </div>
        )
    });

但是你应该尝试传递一个唯一的 id 而不是一个字符串。

【讨论】:

    【解决方案3】:

    这里是渲染方法的代码 sn-p。 试试看吧。

    *更新 = 使用课程名称作为关键字

    render() {
        const courseList = this.props.courses.map(course => (
            <div key={course.title}></div>
        ));
            
        return (
            <>
                <h2>Courses</h2>
                <div>{courseList}</div>
            </>
        );
    }
                    
    

    【讨论】:

    • 同样的错误:Warning: Each child in a list should have a unique "key" prop.
    【解决方案4】:

    问题就在这里:

    {this.props.courses.map((course, index) => (
    
                        <div key={course[index].title}>{course[index].title}</div>
    
    
                    ))}
    //course in itself is data
    

    解决方案:

    {this.props.courses.map((course, index) => (
    
                        <div key={`${course.title}-${index}`}>{course.title}</div>
    
    
                    ))}
    

    更好的方法是始终注意密钥的唯一 ID

    【讨论】:

    • 嗨,我仍然遇到同样的错误:Warning: Each child in a list should have a unique "key" prop.
    • 试试这个:${course.title}-${index}。更新了我的答案
    • 现在我没有收到任何错误,但页面上没有加载任何数据。
    • 我看不到任何错误。您可以交叉检查或更新此沙箱吗? codesandbox.io/s/quizzical-sun-trvki
    【解决方案5】:

    由于每门课程都有唯一的 ID 字段,所以可以通过 id 作为 key 来解决问题

    render() {
      return (
        <>
          <h2>Courses</h2>
    
    
    
          {this.props.courses.map(course => (
    
            <div key={course.id}>{course.title}</div>
    
    
          ))}
        </>
      );
    }
    

    【讨论】:

    • 同样的错误:Warning: Each child in a list should have a unique "key" prop.
    • 那么courses 数组可能有问题。你试过打印courses吗? JSX 中的 {JSON.stringify(this.props.courses)} 之类的东西。这将有助于解决问题。
    • 是的。它使用 JSON.stringify(this.props.courses) 打印得很好。它出现在页面上。我也在浏览器控制台打印出来了,没有任何问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多