React Hooks“无法读取未定义的属性'setState'”

问题描述 投票:-1回答:1

我正在做一个待办事项清单。我希望我的列表项在打勾时成为直行。因此,我试图制作一个称为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
javascript reactjs react-hooks
1个回答
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;
    }));
}

阅读useState中有关documentation here钩的更多信息>

© www.soinside.com 2019 - 2024. All rights reserved.