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

前置简介

上一节: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()

总结

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

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

猜你喜欢

转载自blog.csdn.net/cainiao1412/article/details/108375106