TodoList组件仅在其状态下有一个待办事项列表,每个组件都有一个text属性和一个done属性。 然后,我们可以在TodoItem组件中呈现待办事项列表。
然后,在TodoItem组件中,我们只渲染带有带有值的输入框的列表项。 如果此待办事项已完成,则该值不可编辑-它是只读的。 然后,我们有一个按钮,可用于“完成”或“未完成”任务。
现在,它在右侧的渲染效果很好,但实际上我们无法在TodoList组件的状态下更改这些内容。 因此,如果我尝试对这些输入元素进行更改,则什么也不会发生。 如果单击“ 完成” ,则按钮上的文本不会更改,应该保持不变。 而且我仍然可以在输入字段中选择文本,如果我可以进行更改,则可以进行编辑
所有这些都需要正确连接。 那就是您的挑战! 这是带有所有源代码的CodePen,供您使用。
分叉笔并尝试找出自己的解决方案! 或继续阅读,我将在下面引导您完成。
解决方案
首先,派生原始CodePen,并给它一个不同的名称,例如,添加“ MY SOLUTION”。
我们在这里需要做几件不同的事情。 首先,在TodoItem组件内部,我们需要能够对此数据进行更改。 这意味着我们需要为按钮提供一个onClick处理程序,为输入元素提供一个onChange处理程序。
但是,然后我们需要一种将这些更改传递回父TodoList组件的方法。 因此,这意味着TodoList需要将一个函数向下传递给TodoItem ,以便它可以调用该函数。
创建一个updateTodo函数
因此,我们首先在TodoList添加一个带有一些虚拟文本的updateTodo函数, TodoList我们将对其进行更新。 现在我们已经创建了updateTodo ,我们可以在TodoItem使用它。
那么这将如何工作? 好吧,让我们从按钮开始。 我们将添加一个onClick处理程序,并添加this.handleClick 。
所以现在我们需要编写handleClick函数。 handleClick函数将对传递给TodoItem的todo属性进行TodoItem 。
单击此按钮后,我们希望反转done的值。 因此,如果为假,请将其切换为true,如果为true,则将其切换为false。 然后,当然,我们希望通过updateTodo函数将新近更新的todo对象传递回去。
我们可以通过执行Object.assign来获取newTodo ,这样我们就不会变异数据。 然后,我们将复制现有待办事项中的所有属性,实际上是this.props.todo 。
但是,接下来我们要确保我们覆盖done属性,它应该是this.props.todo.done的反方向或负值。
这就是我们的newTodo 。 然后我们可以做this.props.updateTodo ,我们将通过它我们newTodo 。
确定,因此可以处理点击。 现在,让我们继续并立即编写我们的updateTodo ,以便我们实际可以看到它的作用。 现在,如果我单击Finish ,您可以看到新的待办事项对象是在完成设置为true的地方打印出来的,但是我们尚未在UI中看到这一点。 这是因为,现在,我们需要保存这个新todo回到我们的todos的状态。
设定状态
因此,让我们继续编写一个updateTodo函数,它将把newTodo作为其参数。 在其中,我们将执行this.setState 。
现在,我将以一种您以前从未见过的方式设置状态。 我们将传递一个函数来设置状态,而不是传递一个对象。 实际上,这在React中被认为是一种很好的做法,并且可能是将来设置状态的唯一方法。 传递给setState的函数将接收当前状态作为参数。 因此,我们可以将该状态作为此函数的参数来接收,然后从该函数返回新状态。
实际上,这是创建基于旧状态的新状态的更可靠方法。 在我们的setState调用中,您几乎可以将其视为一种reducer函数。
因此,我们将继续并在此处返回一个新对象。 既然这就是我们要通过该函数执行的所有操作,则实际上我们可以将花括号括在括号中,以便它知道这是一个对象而不是功能块。
让我们获取现有的state.todos ,然后在该处映射每个todo ,如果todo.id等于newTodo.id ,那么我们知道这是我们必须替换的todo对象。 因此,我们可以将它替换为newTodo ,否则我们可以只返回旧的todo ,因为它不是我们要替换的那个。
然后我们只需要更改我们的updateTodo函数以引用this.updateTodo 。
现在,如果单击Finish ,您将看到该按钮变为Unfinish ,这是因为todo.done现在为true而不是false。 另外,“洗车场”文本现在也变灰了,并且不再可编辑。 如果单击未完成 ,它将切换回完成,并且该文本框可以再次编辑。