表单的受控绑定
表单的受控绑定在我看来其实就是数据的双向绑定,我们定义的状态变量值可以影响input输入框的内容,同时input输入框的内容改变也会同时存储到状态变量当中,实现的关键点有两个。
- 创建状态变量,将变量绑定到input框的value属性上,实现从变量到input框的数据绑定
- 利用onChange事件,通过event.target.value将数据更新到状态变量上,实现从input框到变量的数据流动,最终两个步骤实现了数据的双向绑定。
import { useState } from 'react'; function App() { const [text, setText] = useState('') const handleChange = (e) => { setText(e.target.value) } return ( <div> <input type='text' value={text} onChange={handleChange}></input> <p>{text}</p> </div> ); } export default App;
如图所示,当我们改变输入框内容时,下面的文字内容也会跟着一起改变。
获取DOM元素
在一些场景当中我们也需要获取并操作DOM元素,在这里React提供了useRef的钩子函数,获取DOM元素的一般流程如下:
- 使用useRef(null)定义变量
- 将变量绑定到所需要的获取的元素的ref属性上
- 使用变量上的.current就会指向该DOM元素(注意:需要在DOM加载完毕时才能够获取到,)
// 获取并打印DOM元素 import { useRef } from 'react'; function App() { const htmlElement = useRef(null) const getDomElement = () => { console.log(htmlElement.current) } return ( <div> <span ref={htmlElement}>this is the element we need</span> <button onClick={getDomElement}>Get span</button> </div> ); } export default App;
点击按钮后确实获取到了我们所需要的span标签。
案例分析
在本篇文章将会分析列表渲染,删除功能,tab的切换功能以及列表的排序,通过输入框插给列表插入新的信息。
列表渲染与删除单项
列表渲染已经在前期的入门教程中介绍过了,该部分的重点将会聚焦于删除列表元素并让视图重新渲染。
下面所示是列表渲染的基础代码(不要忘记绑定key~~),我们构建了一个简单的列表,包含id、姓名和每个人的年龄。
import { useState } from 'react';
function App() {
// 列表包含id、name、age属性
const users = [
{ id: 1, name: 'Alice', age: 20 },
{ id: 2, name: 'Bob', age: 21 },
{ id: 3, name: 'Charlie', age: 22 }
]
// 创建状态变量
const [list, setList] = useState(users)
return (
<div className="App">
{/* 列表渲染list */}
<ul>
{list.map((user) => (
<li key={user.id}>{user.name} - {user.age}</li>
))}
</ul>
</div>
);
}
export default App;
实现效果如下图所示。
接下来实现删除按钮,在<li>元素内新增一个button元素,设置点击事件,传递的参数是该元素的id,删除函数内部实现使用filter函数,返回匹配的元素组成的新的数组,调用setList函数更新list值的同时触发渲染浏览器视图。
新增button按钮。
return (
<div className="App">
{/* 列表渲染list */}
<ul>
{list.map((user) => (
<li key={user.id}>{user.name} - {user.age}<button onClick={()=>handleDel(user.id)}>Delete</button></li>
))}
</ul>
</div>
处理点击事件的函数。
const handleDel = (id) => {
setList(list.filter((user) => user.id !== id))
}
Tab切换列表排序
接着沿用刚刚定义的列表,首先将排序打乱,我们的Tab分别可以按照年龄排序或者按照id排序,在该部分我们实现的思路是:
第一,通过列表渲染出Tab,每个Tab包含一个type信息,再绑定点击事件的时候我们将type信息传递进入处理点击事件的函数,们需要一个状态变量来存储type信息,在触发点击事件的时候,type的值改变的同时通过使用三元运算符(或者与运算符)控制className实现类名的动态添加,从而实现Tab的样式切换。
第二,type传入处理函数的时候,根据if条件语句排序list,调用setList,触发页面的重新渲染。
import { useState } from 'react';
import './index.css'
function App() {
// 列表包含id、name、age属性
const users = [
{ id: 3, name: 'Alice', age: 50 },
{ id: 2, name: 'Bob', age: 44 },
{ id: 5, name: 'Charlie', age: 18 }
]
// 创建状态变量
const [list, setList] = useState(users)
// 定义删除函数
const handleDel = (id) => {
setList(list.filter((user) => user.id !== id))
}
// 定义tablist
const tabList = [
{ type:'id', content:'根据ID排序'},
{ type:'age', content:'根据年龄排序'}
]
const [type, setType] = useState('id')
const handleTabChange = (type) => {
setType(type)
setList([...list].sort((a, b) => {
return type === 'id' ? a.id - b.id : a.age - b.age
}))
}
return (
<div className="App">
{
tabList.map((tab) => (
<span key={tab.type} onClick={()=>handleTabChange(tab.type)} className={`tab ${type === tab.type ? 'active' : ''}`}>{tab.content}</span>
))
}
{/* 列表渲染list */}
<ul>
{list.map((user) => (
<li key={user.id}>{user.name} - {user.age}<button onClick={()=>handleDel(user.id)}>Delete</button></li>
))}
</ul>
</div>
);
}
export default App;
补充:在index.css定义了基础的样式,如下所示。
.tab {
display: inline-block;
margin-right: 10px;
cursor: pointer;
}
.active {
color: red;
}
新增列表元素
新增列表元素使用到了我们上面刚刚学过的Input数据双向绑定以及获取DOM元素。获取DOM元素主要用于再次在输入框获得焦点。
首先让我们来看看如何通过表单受控绑定实现新增列表元素(代码只展示新增内容)。
const[textVal, setTextVal] = useState('')
const handleInput = (e) => {
setTextVal(e.target.value)
}
const handelAddListItem = () =>{
setList([...list, {id: list.length + 1, name: textVal, age: 20}])
setTextVal('')
}
在JSX中新增下面的代码内容,主要就是应用表单受控绑定。
<input type='text' value={textVal} onChange={handleInput}></input>
<button onClick={handelAddListItem}>Add</button>
这两以来我们就能随意增加内容啦!!!
然后我们需要在点击Add按钮后依然让焦点在输入框内,主要需要两点:
- 获取DOM元素
- 调用.focus方法
新增的代码如下所示,主要就是定义inputRef和input元素绑定ref属性用于获取DOM元素,textVal.current.focus()用于聚焦。
const inputRef = useRef(null)
const handelAddListItem = () =>{
setList([...list, {id: list.length + 1, name: textVal, age: 20}])
setTextVal('')
textVal.current.focus()
}
<input type='text' value={textVal} onChange={handleInput} ref={inputRef}></input>