反应独特 "key" 错误
React unique "key" error
我正在阅读 React 中的待办事项列表教程,运行 出现以下错误,我花了很多时间,就是找不到错误..这是错误和组件的代码,这是课程回购的代码(此提交出现问题):
https://github.com/andrewjmead/react-course-todo-app/commit/0521f151705f78cb9f8d69262eb093f1431cb9ca
非常感谢任何帮助。
警告:数组或迭代器中的每个 child 都应该有一个唯一的 "key" 属性。检查 TodoList
的渲染方法。参见 fb.me/react-warning-keys 了解更多信息。
终端也有错误,对于散布运算符,如果 TOGGLE_TODO
return {
...todo, // here
completed: nextCompleted,
completedAt: nextCompleted ? moment().unix() : undefined
};
var React = require('react');
var { connect } = require('react-redux');
import Todo from 'Todo';
var TodoAPI = require('TodoAPI');
export var TodoList = React.createClass ({
render: function() {
var { todos, showCompleted, searchText } = this.props;
var renderTodos = () => {
if(todos.length === 0) {
return (
<p className="container__message">No tasks</p>
);
}
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => {
return (
//add unique key prop to keep track of individual components
<Todo key={todo.id} {...todo} />
);
});
};
return (
<div>
{renderTodos()}
</div>
);
}
});
export default connect(
(state) => {
return state;
}
)(TodoList);
减速器:
var uuid = require('uuid');
var moment = require('moment');
export var searchTextReducer = (state = '', action) => {
switch (action.type) {
case 'SET_SEARCH_TEXT':
return action.searchText;
default:
return state;
};
};
export var showCompletedReducer = (state = false, action) => {
switch (action.type) {
case 'TOGGLE_SHOW_COMPLETED':
return !state;
default:
return state;
};
};
export var todosReducer = (state = [], action) => {
switch(action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
id: uuid(),
completed: false,
createdAt: moment().unix(),
completedAt: undefined
}
];
case 'TOGGLE_TODO':
return state.map((todo) => {
if(todo.id === action.id) {
var nextCompleted = !todo.completed;
return {
...todo,
completed: nextCompleted,
completedAt: nextCompleted ? moment().unix() : undefined
};
} else {
return todo;
}
});
case 'ADD_TODOS':
return [
...state,
...action.todos
];
default:
return state;
}
};
Webpack:
var webpack = require('webpack');
module.exports = {
entry: [
'script!jquery/dist/jquery.min.js',
'script!foundation-sites/dist/js/foundation.min.js',
'./app/app.jsx'
],
externals: {
jquery: 'jQuery'
},
plugins: [
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery'
})
],
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
modulesDirectories: [
'node_modules',
'./app/components',
'./app/api'
],
alias: {
applicationStyles: 'app/styles/app.scss',
actions: 'app/actions/actions.jsx',
reducers: 'app/reducers/reducers.jsx',
configureStore: 'app/store/configureStore.jsx'
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
},
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/
}
]
},
devtool: 'cheap-module-eval-source-map'
};
我打赌 todo.id
是 undefined
,因此不是唯一的。您可以在示例中包含 todos
吗?
您可以将 index
参数添加到您的 map
函数,然后将该索引传递给您的 Todo
组件:
export var TodoList = React.createClass ({
render: function() {
var { todos, showCompleted, searchText } = this.props;
var renderTodos = () => {
if(todos.length === 0) {
return (
<p className="container__message">No tasks</p>
);
}
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo, index) => { // here <====
return (
//add unique key prop to keep track of individual components
<Todo key={`key-${index}`} {...todo} />
);
});
};
return (
<div>
{renderTodos()}
</div>
);
}
});
在 React 中,当您渲染多个相同的组件(在您的例子中是待办事项)时,您需要为每个组件添加一个唯一的键,这是因为 React 需要知道它们将如何在虚拟 dom.
您可以采取多种措施来解决此问题:
在 for 循环中,创建一个索引变量,并在每次循环结束时将其递增 1,然后将其设置为每个渲染组件的键。
如果您从 api 获取待办事项,请为每个待办事项设置一个 ID 并将其用作您的组件键。
使用 运行dom 数字生成器为每个待办事项设置唯一键。
最好的方法是#2 和#3,我看到在你的情况下你正在尝试执行#2(通过 todo id 设置密钥)但我认为它是未定义的,检查它。
另一个解决方案是在每个渲染 component/todo.
上使用 uuid
为此,您可以安装 node-uuid。
运行: npm i --save node-uuid
然后在您的文件中导入:import uuid from 'node-uuid'
或 const uuid = require('node-uuid')
现在把你的代码改成这样:
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => {
return (
//add unique key prop to keep track of individual components
<Todo key={uuid()} {...todo} />
);
});
然后就可以开始了。
node-uuid 已弃用,请查看此处:https://www.npmjs.com/package/uuid
您可以通过安装 uuid 更新您的 package.json,看看是否有帮助:
npm 安装 uuid
只是不要忘记更新 var uuid = require('node-uuid');到 var uuid = require('uuid');在你的其他文件中。
P.S。当你 运行 一个 webpack 时,你的终端有任何错误吗?
我正在阅读 React 中的待办事项列表教程,运行 出现以下错误,我花了很多时间,就是找不到错误..这是错误和组件的代码,这是课程回购的代码(此提交出现问题):
https://github.com/andrewjmead/react-course-todo-app/commit/0521f151705f78cb9f8d69262eb093f1431cb9ca
非常感谢任何帮助。
警告:数组或迭代器中的每个 child 都应该有一个唯一的 "key" 属性。检查 TodoList
的渲染方法。参见 fb.me/react-warning-keys 了解更多信息。
终端也有错误,对于散布运算符,如果 TOGGLE_TODO
return {
...todo, // here
completed: nextCompleted,
completedAt: nextCompleted ? moment().unix() : undefined
};
var React = require('react');
var { connect } = require('react-redux');
import Todo from 'Todo';
var TodoAPI = require('TodoAPI');
export var TodoList = React.createClass ({
render: function() {
var { todos, showCompleted, searchText } = this.props;
var renderTodos = () => {
if(todos.length === 0) {
return (
<p className="container__message">No tasks</p>
);
}
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => {
return (
//add unique key prop to keep track of individual components
<Todo key={todo.id} {...todo} />
);
});
};
return (
<div>
{renderTodos()}
</div>
);
}
});
export default connect(
(state) => {
return state;
}
)(TodoList);
减速器:
var uuid = require('uuid');
var moment = require('moment');
export var searchTextReducer = (state = '', action) => {
switch (action.type) {
case 'SET_SEARCH_TEXT':
return action.searchText;
default:
return state;
};
};
export var showCompletedReducer = (state = false, action) => {
switch (action.type) {
case 'TOGGLE_SHOW_COMPLETED':
return !state;
default:
return state;
};
};
export var todosReducer = (state = [], action) => {
switch(action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
id: uuid(),
completed: false,
createdAt: moment().unix(),
completedAt: undefined
}
];
case 'TOGGLE_TODO':
return state.map((todo) => {
if(todo.id === action.id) {
var nextCompleted = !todo.completed;
return {
...todo,
completed: nextCompleted,
completedAt: nextCompleted ? moment().unix() : undefined
};
} else {
return todo;
}
});
case 'ADD_TODOS':
return [
...state,
...action.todos
];
default:
return state;
}
};
Webpack:
var webpack = require('webpack');
module.exports = {
entry: [
'script!jquery/dist/jquery.min.js',
'script!foundation-sites/dist/js/foundation.min.js',
'./app/app.jsx'
],
externals: {
jquery: 'jQuery'
},
plugins: [
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery'
})
],
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
modulesDirectories: [
'node_modules',
'./app/components',
'./app/api'
],
alias: {
applicationStyles: 'app/styles/app.scss',
actions: 'app/actions/actions.jsx',
reducers: 'app/reducers/reducers.jsx',
configureStore: 'app/store/configureStore.jsx'
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
},
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/
}
]
},
devtool: 'cheap-module-eval-source-map'
};
我打赌 todo.id
是 undefined
,因此不是唯一的。您可以在示例中包含 todos
吗?
您可以将 index
参数添加到您的 map
函数,然后将该索引传递给您的 Todo
组件:
export var TodoList = React.createClass ({
render: function() {
var { todos, showCompleted, searchText } = this.props;
var renderTodos = () => {
if(todos.length === 0) {
return (
<p className="container__message">No tasks</p>
);
}
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo, index) => { // here <====
return (
//add unique key prop to keep track of individual components
<Todo key={`key-${index}`} {...todo} />
);
});
};
return (
<div>
{renderTodos()}
</div>
);
}
});
在 React 中,当您渲染多个相同的组件(在您的例子中是待办事项)时,您需要为每个组件添加一个唯一的键,这是因为 React 需要知道它们将如何在虚拟 dom.
您可以采取多种措施来解决此问题:
在 for 循环中,创建一个索引变量,并在每次循环结束时将其递增 1,然后将其设置为每个渲染组件的键。
如果您从 api 获取待办事项,请为每个待办事项设置一个 ID 并将其用作您的组件键。
使用 运行dom 数字生成器为每个待办事项设置唯一键。
最好的方法是#2 和#3,我看到在你的情况下你正在尝试执行#2(通过 todo id 设置密钥)但我认为它是未定义的,检查它。
另一个解决方案是在每个渲染 component/todo.
上使用 uuid为此,您可以安装 node-uuid。
运行: npm i --save node-uuid
然后在您的文件中导入:import uuid from 'node-uuid'
或 const uuid = require('node-uuid')
现在把你的代码改成这样:
return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => {
return (
//add unique key prop to keep track of individual components
<Todo key={uuid()} {...todo} />
);
});
然后就可以开始了。
node-uuid 已弃用,请查看此处:https://www.npmjs.com/package/uuid
您可以通过安装 uuid 更新您的 package.json,看看是否有帮助:
npm 安装 uuid
只是不要忘记更新 var uuid = require('node-uuid');到 var uuid = require('uuid');在你的其他文件中。
P.S。当你 运行 一个 webpack 时,你的终端有任何错误吗?