[英]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.