React notes components-the use of complex state (4)

Introduction

Previous section: https://juejin.im/post/6867454175781847047

We briefly talked about the use of state, and this section explains the use of complex state.

What if there is more than n in state?

There are multiple values ​​in the state of the class component

<!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>

You can see the results of the operation, click the m+1 button to call the addM method, and click n+1 to call the addN method. Here are all normal.

But pay attention to detail that is addN | M method we use to this.setState only for their individual value assignment to do a modification, for example, this.setState({n: this.state.n + 1})where we did not go to Settings m, only set n, m but in this set After that, it exists in the view,

This is because React will automatically copy the value in our previous state to this state object, and then replace n with the latest n, similar to

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

So we only set n, and m is also retained.

Let's summarize this phenomenon: the setState of the class component will automatically merge the first-level attributes.

The following is a special note, the setState of the class component will not merge the second-level attributes.

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()

Looking at the above effect and code, user is an object in state. When we modify m and n, the attributes of user are normal.

But when we modify the user's name, but do not set age, the age is lost. This is the reason why the second-level attributes will not be merged.

If you don't write the second-level attribute, React directly thinks that you don't need this attribute, so it is gone. You need to merge it manually by yourself, as follows:

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

Or use the Object.assign method to combine values.

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

There are multiple values ​​in the state of the function component

Change the above class App component to a function component, as follows

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>
    )
}

The effect is the same, but the writing method is much more convenient than the class component, so it is recommended that you write function components.

There is also a non-recommended way of writing function components. Put m and n in the same object:

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"))
}

We save m and n at the same time through the state object, let's see the effect:

Click m+1 first, then n+1, n becomes NaN,

This is because when the object is set here, m is set, and the value of n is lost and becomes undefined, so there is a problem with n.

It should be remembered here that the setState of the function component will not automatically merge the attributes. It is possible for the class component, so if the function component uses an object to save all the values, when you setState again, you must merge the attributes first. setState({...state,m: state.m + 1})

Just change it like this.

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()

to sum up

  1. The setState of the class component will automatically merge the first-level attributes, but will not merge the second-level attributes. Use the ... operator or Object.assign to merge the second-level attributes yourself.

  2. The setX of the function component will not automatically merge any attributes, and handle it manually.

Guess you like

Origin blog.csdn.net/cainiao1412/article/details/108375106