React Hooks "Не удается прочитать свойство 'setState' из неопределенного" - PullRequest
0 голосов
/ 30 апреля 2020

Я делаю список дел. Я хочу, чтобы элементы моего списка становились сквозными, когда я отмечал этот флажок. Поэтому я пытаюсь сделать const под названием markComplete. Я использую компонентное бурение, посылая свои реквизиты из компонента «TodoItem» в «Todos» в «App».

Проблема: в markComplete я пытаюсь получить доступ к this, потому что хочу изменить состояние проверенного элемента списка. Хотя из-за того, что я использую Хуки в этом проекте + тот факт, что я немного новичок, я изо всех сил пытаюсь найти решение для ошибки «Не удается прочитать свойство 'setState' из неопределенного». Ссылка на мою ошибку

Так что я считаю, что с Hooks setState () больше не является чем-то особенным. Я думаю, что нужно использовать useEffect(), но я не уверен. Возможно, это как-то связано с привязкой, но я связываюсь в TodoItem и использую функции стрелок.

Может ли кто-нибудь быстро взглянуть на мой код и сказать, чего мне здесь не хватает? Спасибо в связи.

Приложение. 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

1 Ответ

2 голосов
/ 30 апреля 2020

Вы пытаетесь использовать this.setState в функциональном компоненте App. Вместо этого вам нужно использовать setTodos, который задает состояние ваших задач. Также используйте подход обратного вызова для обновления состояния, поскольку ваше текущее состояние зависит от предыдущего состояния

const markComplete = (id) => {
    console.log(id);

    setTodos(prevTodos => prevTodos.map(todo => {
      if(todo.id === id) {
        todo.completed =! todo.completed
      }
      return todo;
    }));
}

Подробнее о useState ловушке в документации здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...