让我们继续扩展我们的应用,允许用户添加新的便笺。
先将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 --
<input
value={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组件的数据和方法,这有什么优点和缺点?