TodoApp - 使用索引切换待办事项时遇到问题

TodoApp - trouble with toggle todo using index

我正在尝试通过单击 li 来切换单个待办事项。

我最初是通过在 Todo class 组件上建立一个状态并从那里修改它来做到这一点的,从那时起我将状态移动到 TodoApp 组件。

我可以通过用 1 指定索引号来切换单个待办事项,它会用索引 1 来切换待办事项,但是我似乎无法弄清楚如何获取单击的 li 元素的索引。我的 li 元素嵌套在 Todo 组件中。

如果我在 onClick={() => this.props.toggleTodo(i)} 中将索引保留为 (i),我得到一个错误,

./src/index.js 第 12 行:'i' 未定义 no-undef

如何将索引从我的 List 组件正确传递到正在 Todo 组件中执行的 this.props.toggleTodo() 函数?

如有任何帮助,我们将不胜感激!

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import registerServiceWorker from './registerServiceWorker';

// initializing todo
class Todo extends React.Component {
    render() {
        return (
            <ul>
                <li className="todo" 
                    onClick={() => this.props.toggleTodo(i)}>
                    <span className="btn-completed" style={{color: this.props.completed ? '#99cc99' : '#fafafa'}}>{'\u{2714}'}</span>
                    <span style={{textDecoration: this.props.completed ? 'line-through' : 'none'}}>{this.props.text}</span>
                    <span className="btn-delete" onClick={() => this.props.onClick(this.props.id)} >{'\u{2716}'}</span>
                </li>
            </ul> 
        )
    }
}

// initializing list of todos
const List = (props) => (
    <div>
        {props.todos.map((todo, i) => <Todo key={todo.id} onClick={props.onClick} toggleTodo={props.toggleTodo} {...todo}/>)}
    </div>
)

// initializing form
const Form = (props) => (
    <form onSubmit={props.onSubmit}>
        <input type="text" autoFocus required placeholder="Enter Todo..."
            value={props.value}
            onChange={props.onChange}
        />
    </form>
)

// initializing main app
class TodoApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            inputText: '',
            todos: []
        }
        this.onChange = this.onChange.bind(this);
        this.addTodo = this.addTodo.bind(this);
        this.filterTodo = this.filterTodo.bind(this);
        this.toggleAll = this.toggleAll.bind(this);
        this.toggleTodo = this.toggleTodo.bind(this);
    }

    //getting text input value
    onChange = (e) => {
        this.setState({inputText: e.target.value})
    }

    // adding todo
    addTodo = (e) => {
        e.preventDefault();

        const newTodos = this.state.todos.concat([{text: this.state.inputText, id: Date.now(), completed: false}])
        this.setState({inputText: '', todos: newTodos},
            () => console.log(this.state.todos)
        )
    }

    // filtering todo
    filterTodo = (id) => {
        const filteredTodos = this.state.todos.filter((item) => item.id !== id);
        this.setState({todos: filteredTodos});
    }

    toggleAll = () => {
        const newTodos = this.state.todos;
        newTodos.forEach(todo =>
            todo.completed = !todo.completed
        )
        this.setState({todos: newTodos}, () => console.log(this.state.todos))
    }

    toggleTodo(i) {
        const newTodos = this.state.todos;
        newTodos[i].completed = !newTodos[i].completed
        this.setState({todos: newTodos});
    }

    // rendering view
    render() {
        return (
            <div>
                <Form
                    value={this.state.inputText}
                    onChange={this.onChange}
                    onSubmit={this.addTodo}
                />
                <button onClick={() => this.toggleTodo(1)}>Toggle All</button>
                <List
                    toggle={this.toggleTodo}
                    todos={this.state.todos}
                    onClick={this.filterTodo} 
                    />
            </div>
        );
    }
}

ReactDOM.render(<TodoApp />, document.getElementById('root'));
registerServiceWorker();

这应该适合你:

const List = (props) => (
    <div>
        {props.todos.map((todo, i) => <Todo key={todo.id} onClick={props.onClick} toggleTodo={() => props.toggle(i)} {...todo}/>)}
    </div>
)

执行此操作后,您无需使用 Todo 中的 i,因为传入的函数已经特定于数组中的特定元素。

onClick={() => this.props.toggleTodo()}>

但是,我认为如果您使用修改后的 toggleTodo 方法会更好,这样它在您执行类似操作时就可以工作,但这需要某种查找:

onClick={() => this.props.toggleTodo(this.props.id)}

编辑:删除停止工作,因为 onClick 事件发生在 li 上。绕过它的一个简单方法是:

<li className="todo">
  <span onClick={() => this.props.toggleTodo(i)}>
    <span className="btn-completed" style={{color: this.props.completed ? '#99cc99' : '#fafafa'}}>{'\u{2714}'}</span>
    <span style={{textDecoration: this.props.completed ? 'line-through' : 'none'}}>{this.props.text}</span>
  </span>
  <span className="btn-delete" onClick={() => this.props.onClick(this.props.id)} >{'\u{2716}'}</span>
</li>