让我们继续扩展我们的应用,允许用户添加新的便笺。
先将notes存储在App的状态中
import React, { useState } from 'react'import Note from './components/Note'const App = (props) => {const [notes, setNotes] = useState(props.notes)const addNote = (event) => {event.preventDefault()console.log('button clicked', event.target)}return (<div><h1>Notes</h1><ul>{notes.map(note =><Note key={note.id} note={note} />)}</ul><form onSubmit={addNote}><input /><button type="submit">save</button></form></div>)}export default App;
表单的submit默认会导致页面刷新,event.preventDefault()阻止页面刷新
让我们添加一个名为 newNote 的新状态,用于存储用户提交的输入,让我们将它设置为input 元素的value 属性:
-- snip --const App = (props) => {const [notes, setNotes] = useState(props.notes)const [newNote, setNewNote] = useState('a new note...')-- snip --return (<div>-- snip --<form onSubmit={addNote}><input value={newNote} /><button type="submit">save</button></form></div>)}export default App;
此时input 不能编辑输入文本。 而且控制台出现了一个警告
由于我们将App 组件的一部分状态指定为 input 元素的value 属性,因此App 组件现在控制 了input 元素的行为。
为了能够编辑 input 元素,我们必须注册一个事件处理 来同步对 input 所做的更改和组件的状态:
-- snip --const handleNoteChange = (event) => {console.log(event.target.value)setNewNote(event.target.value)}-- snip --<inputvalue={newNote}onChange={handleNoteChange}/>
安装的React Devtool 可以查看到state的值
修改addNote, 将新的note添加进notes
- 用concat创建新的数组
最后setNewNote(‘’)将input的值清空
const addNote = (event) => {event.preventDefault()const noteObject = {content: newNote,date: new Date().toISOString(),important: Math.random() < 0.5,id: notes.length + 1,}setNotes(notes.concat(noteObject))setNewNote('')}
以上将input的value与App组件的状态绑定,并添加onChange事件更新状态的方法,称为受控组件
Filtering Displayed Elements 过滤显示元素
新建一个showAll状态存储是否过滤
- 用filter方法过滤,返回符合回调函数返回值为true的元素组成的数组 ```javascript — snip —
const App = (props) => { — snip — const [showAll, setShowAll] = useState(true)
const notesToShow = showAll ? notes : notes.filter(note => note.important)
— snip —
return (
Notes
-
{notesToShow.map(note =>
export default App;
<a name="fUpao"></a>### exercise 2.6 - 2.10有时,为了调试目的,将状态和其他变量作为文本渲染出来会很有用。 您可以临时向渲染的组件添加如下元素:```javascript<div>debug: {newName}</div>
phonebook实现添加姓名
import React, { useState } from 'react'const App = () => {const [persons, setPersons] = useState([{ name: 'Arto Hellas' }])const [newName, setNewName] = useState('')const handleNameChange = (event) => {setNewName(event.target.value)}const handleSubmit = (event) => {event.preventDefault()setPersons([...persons, { name: newName }])}return (<div><div>debug: {newName}</div><h2>Phonebook</h2><form onSubmit={handleSubmit}><div>name: <input value={newName} onChange={handleNameChange} /></div><div><button type="submit">add</button></div></form><h2>Numbers</h2>{persons.map(item => <div key={item.name}>{item.name}</div>)}</div>)}export default App
当名称重复时,给出提醒
const handleSubmit = (event) => {event.preventDefault()const names = persons.map(item => item.name)if (names.indexOf(newName) >= 0) {alert(`${newName}已存在`)} else {setPersons([...persons, { name: newName }])}}
实现过滤姓名
const handleFilterName = (event) => {const name = event.target.value.toLowerCase()const names = persons.filter(item => item.name.toLowerCase().indexOf(name) >= 0)setFilterPersons(names)setFilterFlag(true)}

思考:到目前为止,state和方法都是在App组件里,子组件都只是调用App组件的数据和方法,这有什么优点和缺点?
