簡體   English   中英

地圖在 React 中的第一次迭代后停止迭代

[英]Map stops iterating after first iteration in React

我的組件應該在組件安裝時檢索課程數據。 我遇到的問題是,無論我使用課程 ID 還是課程標題​​作為鍵,我都會收到以下錯誤:

index.js:1 警告:列表中的每個子項都應該有一個唯一的“鍵”屬性。

我已經瀏覽了 Stack Overflow 上的 react 文檔,並嘗試了不同的方法來讓它工作。 我可以讓它部分工作的唯一方法是添加一個索引作為 map 的參數。 當我使用這種方法時,我遇到了另一個問題,即它在第一次迭代后停止,即使有 10 個項目。 我怎樣才能解決這個問題?

這是我的代碼:

課程頁面.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;
    }
}

任何幫助,將不勝感激。

謝謝。

PS 我知道你應該使用 Id 作為密鑰。 但是現在必須完成的方法是使用課程的標題作為關鍵。

通過您的編輯,我認為我們可以更有效地幫助您。 對於未來,發布一個您的代碼在https://codesandbox.io/ 上不起作用的示例將是有益的

同樣為了在調試時幫助自己,將 react 組件與 redux 的使用隔離開來。 這將允許您確保您的 react 組件在給定數據時呈現,然后專注於獲取 redux 以提供您的 react 組件擁有的數據。

您可以先在 react 組件中定義模擬數據,然后將模擬數據移動到減速器,最后用實時 api 調用替換模擬數據。

上代碼:

您有兩個問題:第一個是您想要索引到數組courses但由於拼寫錯誤,您實際上是在對象course使用屬性訪問器

key={course[index].title}

正如您的問題所述,您必須使用標題作為鍵,只需將 div 更改為:

<div key={course.title}>{course.title}</div>並且您的代碼應該按預期工作。

一旦你解決了這個問題,然后使用 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];

問題在這里:

{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

由於每門課程都有一個唯一的ID字段,因此可以使用id作為key來解決問題

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



      {this.props.courses.map(course => (

        <div key={course.id}>{course.title}</div>


      ))}
    </>
  );
}

有很多方法可以在迭代時傳遞密鑰......

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 而不是字符串。

這是 render 方法的代碼片段。 試一試。

*更新=使用課程標題作為關鍵

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM