React笔记之组件-复杂state的使用(4)

tech2022-09-15  62

前置简介

上一节:https://juejin.im/post/6867454175781847047

我们简单说了state的使用,本节说明一下复杂的state使用方式。

如果state里不止有 n 怎么办?

类组件中 state 中有多个值

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> </head> <body> <div id="root"> </div> <script src="https://cdn.bootcdn.net/ajax/libs/react/16.9.0/umd/react.development.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.9.0/umd/react-dom.development.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script> <script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { n: 0, m: 0 } } addN() { this.setState({n: this.state.n + 1}) } addM() { this.setState({m: this.state.m + 1}) } render() { return ( <div> m: {this.state.m} <button onClick={() => {this.addM()}}>m+1</button> n: {this.state.n} <button onClick={() => {this.addN()}}>n+1</button> </div> ) } } const render = () => { ReactDOM.render(<App/>, document.querySelector("#root")) } render() </script> </body> </html>

可以看到运行结果,点击m+1按钮调用addM方法,点击n+1调用addN方法,这里都是正常的,

不过要注意一个细节就是在 addN|M 方法中,我们使用 this.setState 只针对于他们单独的值做了赋值修改,例如 this.setState({n: this.state.n + 1}) 这里我们就没去设置m,只设置了n,但是m在这次设置后,以然存在于视图中,

这是因为React会自动将我们之前state中的值,拷贝到本次state对象中来,然后把n 换成 最新的 n,类似于

this.setState({n: this.state.n + 1}) = this.setState({...this.state , n: this.state.n + 1})

所以我们只设置了n,m也得以保留。

这个现象我们总结一下就是:类组件的 setState 会自动合并第一层属性。

下面要说一个特别需要注意的,类组件的 setState 不会合并第二层属性。

class App extends React.Component { constructor() { super(); this.state = { n: 0, m: 0, user: { name: 'lili', age: 18 } } } addN() { this.setState({n: this.state.n + 1}) } addM() { this.setState({m: this.state.m + 1}) } changeUser() { this.setState({user: { name: 'fangfang', // age被清空了 } }) } render() { return ( <div> name: {this.state.user.name}, age: {this.state.user.age} <button onClick={() => {this.changeUser()}}>changeUser</button> <br/> m: {this.state.m} <button onClick={() => {this.addM()}}>m+1</button> n: {this.state.n} <button onClick={() => {this.addN()}}>n+1</button> </div> ) } } const render = () => { ReactDOM.render(<App/>, document.querySelector("#root")) } render()

看上面的效果和代码,user是state中的一个对象,当我们修改m 和 n的时候,user的属性都是正常的,

但是当我们修改user的name,却并没有设置age时,age丢失了,这个就是第二层属性不会合并的由来,

二层属性不写的话,React直接认为你丢失不要这个属性了,所以就没有了,需要自己手动合并,如下:

this.setState({user: { ...this.state.user, name: 'fangfang' } })

或者用 Object.assign 方法来合并值。

const user = Object.assign({},this.state.user) user.name = 'fangfang' this.setState({user: user})

函数组件中 state 中有多个值

将上面的类App组件改为函数组件,如下

const App = () => { const [n, setN] = React.useState(0) const [m, setM] = React.useState(0) return ( <div> m: {m} <button onClick={() => {setM(m + 1)}}>m+1</button> n: {n} <button onClick={() => {setN(n + 1)}}>n+1</button> </div> ) }

实现的效果是一样的,但是写法就比类组件要方便很多,所以推荐大家写函数组件。

函数组件这里还有一个不推荐的写法,把m和n放到同一个对象里去:

const App = () => { const [state, setState] = React.useState({n: 0, m: 0}) return ( <div> m: {state.m} <button onClick={() => {setState({m: state.m + 1})}}>m+1</button> n: {state.n} <button onClick={() => {setState({n: state.n + 1})}}>n+1</button> </div> ) } const render = () => { ReactDOM.render(<App/>, document.querySelector("#root")) }

我们通过state对象同时保存了m 和 n,看一下效果:

先点 m+1,再点 n+1 , n就变成了NaN,

这是因为这里设置对象的时候,设置m,把n这个值给丢没了,变成了undefined,所以n这里出现了问题。

这里要记住函数组件的 setState 不会自动合并属性,类组件时可以的,所以函数组件这里如果用一个对象保存所有的值,再次setState的时候,一定要先合并属性 setState({...state,m: state.m + 1})

改成这样就可以了。

const App = () => { const [state, setState] = React.useState({n: 0, m: 0}) return ( <div> m: {state.m} <button onClick={() => {setState({...state,m: state.m + 1})}}>m+1</button> n: {state.n} <button onClick={() => {setState({...state,n: state.n + 1})}}>n+1</button> </div> ) } const render = () => { ReactDOM.render(<App/>, document.querySelector("#root")) } render()

总结

类组件的 setState 会自动合并第一层属性,但是不会合并第二层属性,使用 …操作符 或者 Object.assign自己合并第二层属性。

函数组件的setX不会自动合并任何属性,自己手动处理。

最新回复(0)