我正在做一个待办事项清单。我希望我的列表项在选中复选框时成为直行。因此,我试图制作一个称为markComplete的常量。我通过将道具从“ TodoItem”发送到“ Todos”再到“ App”来利用组件钻探。
问题:在markComplete中,我尝试访问this
,因为我想更改检查的列表项的状态。尽管由于我在该项目中使用了Hooks,而且我有点新,但我仍在努力寻找错误“无法读取未定义的属性'setState'”的解决方案。 Link to my error
因此,我相信对于Hooks来说,setState()不再是真正的事情。我认为必须使用useEffect()
,但是我不太确定。它可能与绑定有关,但是我确实在“ TodoItem”中进行绑定,并且确实使用了箭头功能。
有人可以快速浏览一下我的代码,并告诉我我在这里缺少什么吗? 谢谢。
App.js
import React, { useState } from 'react';
import Todos from './components/Todos';
import './App.css';
const App = (props) => {
const [todos, setTodos] = useState(
[
{
id: 1,
title: 'Learn React',
completed: true
},
{
id: 2,
title: 'Eat lunch',
completed: false
},
{
id: 3,
title: 'Meet up with friends',
completed: false
},
]
);
const markComplete = (id) => {
console.log(id);
this.setState([{todos: this.todos.map(todo => {
if(todo.id === id) {
todo.completed =! todo.completed
}
return todo;
})}]);
}
return (
<div className="App">
{/* Todos.js is being called. Also props are being passed in Todos.js. */}
<Todos todos={todos} markComplete={markComplete}/>
</div>
);
}
export default App;
// // Log all todos in objects
// console.log((todos));
// // Log the 1st todo object
// console.log((todos[0]));
// // Log the title of the first todo
// console.log((todos[0].title));
Todos.js
import React from 'react';
import TodoItem from './TodoItem';
import PropTypes from 'prop-types';
function Todos(props) {
// console.log(props.todos)
return (
<div>
<h1>My to do list</h1>
{props.todos.map(todo => { // using props in child component and looping
return (
// Outputting all the titles from todo. It is more clean to make a seperate component for this.
// <li>{todo.title}</li>
// Calling a seperate component called ToDoItem in order to return the titles.
<TodoItem key={todo.id} todo={todo} markComplete={props.markComplete} />
)
})}
</div>
);
}
// Defining proptypes for this class. In app.js, we see that Todos component has a prop called 'todos'. That needs to be defined here.
Todos.propTypes = {
todos: PropTypes.array.isRequired
}
export default Todos;
TodoItem.js
import React, { useCallback } from 'react'
import PropTypes from 'prop-types';
function TodoItem(props) {
// Change style based on state.
// By using useCallback, we can ensure the function App() is only redefined when one of its dependencies changes.
// In this, case that is the dependencie 'completed'.
// If you use id / title in the getStyle as well, you have to define these in the useCallback.
const getStyle = useCallback(() => {
return {
backgroundColor: '#f4f4f4',
padding: '10px',
borderBottom: '1px solid #ccc',
// If-else text decoration based on state
textDecoration: props.todo.completed ?
'line-through' : 'none'
}
}, [props.todo.completed]);
// Destructuring
const { id, title } = props.todo
return (
// Call out a function to change style based on state
<div style={getStyle()}>
<p>
{ /* Start of ladder: passing the state though to Todos.js */ }
{ /* We use bind to see which checkbox is being marked. We use id to make this distinction. */ }
<input type="checkbox" onChange={props.markComplete.bind(this, id)}
/> { ' ' }
{ title }
{props.todo.title}
</p>
</div>
)
}
// Defining proptypes for this class. In Todos.js, we see that TodoItem component has a prop called 'todo'. That needs to be defined here.
TodoItem.propTypes = {
todo: PropTypes.object.isRequired
}
// const itemStyle = {
// backgroundColor: '#f4f4f4'
// }
export default TodoItem
答案 0 :(得分:2)
您正在尝试在App的功能组件中使用this.setState
。相反,您需要使用setTodos
,它是您的待办事项状态的设置器。由于您的当前状态取决于先前的状态,因此也请使用回调方法来更新状态
const markComplete = (id) => {
console.log(id);
setTodos(prevTodos => prevTodos.map(todo => {
if(todo.id === id) {
todo.completed =! todo.completed
}
return todo;
}));
}
详细了解 documentation here
中的useState
钩子