本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
本文主要内容:承接上一篇文章对于 useState 和 setState 的总结,进一步总结如何对较为复杂的state进行操作。
其实在我看来,useState 的核心就是拆解赋值,将方法中的初始值赋给数组中的第一个元素,将处理这个值的函数赋给数组中的第二个元素;setState 的核心是每次通过一个函数更新state的值,无论是不考虑先前的值还是考虑先前的值,本质上都是进行再一次的赋值。所以复杂的state也仅仅只是复杂在类型上,思想上是一定一致的。
数组 state
预览与分析
我们要实现每一次点击 Add Item 按钮,都会在下方新增一个 Thing ,并且它后面的数字也要同步增长。
静态网页实现
直接定义一个数组,然后利用 map 方法解析成为 数组元素带有标签的数组 ,再渲染到页面上即可
所以可以直接看代码如下:
import React from 'react';
export default function App() {
const thingsArray = ["Thing 1", "Thing 2"]
const thingsElements = thingsArray.map(thing => <p key={thing}>{thing}</p>)
return (
<div>
<button>Add Item</button>
{thingsElements}
</div>
)
}
使用useState和setState
根据前言中说到,先用 useState 进行初始化的解析赋值,如下
const [thingsArray, setThingsArray] = React.useState(["Thing 1", "Thing 2"])
接下来在button处添加一个鼠标事件,在这个事件函数中使用setState更新数组
所以最终可以这样子写:
import React from 'react';
export default function App() {
const [thingsArray, setThingsArray] = React.useState(["Thing 1", "Thing 2"])
function addItem() {
setThingsArray(prevThingsArray => {
return [...prevThingsArray, `Thing ${prevThingsArray.length + 1}`]
})
}
const thingsElements = thingsArray.map(thing => <p key={thing}>{thing}</p>)
return (
<div>
<button onClick={addItem}>Add Item</button>
{thingsElements}
</div>
)
}
在这里需要使用考虑先前的值的 setState ,每次接收先前的一个数组,再进行解析拆分后放入一个新的数组,同时放入的还有要添加的值
这样将新产生的数组更新掉先前的数组,就能实现 Add Item 的功能
对象 state
预览与分析
这是一张简易的小名片,我们要做的是实现点击那颗星星,然后星星会被填上表示选中
静态网页实现
这里就直接写useState后的静态网页代码了
import React from "react"
export default function App() {
const [contact, setContact] = React.useState({
firstName: "heheer",
lastName: "WANG",
qq: "1239331448",
email: "1239331448@qq.com",
isFavorite: false
})
return (
<main>
<article className="card">
<img src="./images/user.png" className="card--image" />
<div className="card--info">
<img
src={`./images/star.png`}
className="card--favorite"
onClick={toggleFavorite}
/>
<h2 className="card--name">
{contact.firstName} {contact.lastName}
</h2>
<p className="card--contact">qq: {contact.qq}</p>
<p className="card--contact">email: {contact.email}</p>
</div>
</article>
</main>
)
}
可以看到定义了一个对象 contact ,通过访问对象的属性将不同的值渲染到了页面上
我们接下来的目标是通过 setState 修改对象 isFavorite 属性,使得其能通过点击进行 true 和 false 的互换,并且使用三元表达式来选择 img 的 src ,进而修改星星的样式
实现三元表达式
为了使看起来更直观,我们先写 isFavorite 和 star 对应的三元表达式,如下
let starIcon = contact.isFavorite ? "star-fill.png" : "star.png"
所以再对 img 的 src 进行修改
src={`./images/${starIcon}`}
就可以实现简单的对应了
实现对象的setState
接下来就可以在预留的事件函数 toggleFavorite 中使用 setState 实现功能了
所以我们进行如下修改
function toggleFavorite() {
setContact(prevContact => {
return {
isFavorite: !prevContact.isFavorite
}
})
}
接收先前对象的值,将 isFavorite 的值取反,从而实现布尔值的互换
然而实际情况却是这样的
实现了星星的互换确实不假,但是其他的对象属性就直接消失了,这非常不好
原因在于最后只是重新将isFavorite的值重新赋给了对象,而其他属性没能收到值,理所当然的值为空,自然就无法渲染出东西来
所以我们应该同时将所有属性的值重新赋予,再在这个基础上修改 isFavorite,这里可以将对象的每个属性一一列出,不过还是用 ...展开运算符比较方便,最终代码如下
function toggleFavorite() {
setContact(prevContact => {
return {
...prevContact,
isFavorite: !prevContact.isFavorite
}
})
}
实现结果如下