React hooks 学习笔记 - useState

使用hook的好处:
1.可以不再使用class(有状态组件)
2.不用考虑复杂的react生命周期钩子函数
3.让this的处理变得简单

例子

普通版本:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }

使用hooks的版本:

import { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

以下是逐行解析:

import { useState } from 'react';

这一句引入了useState这个hook

 const [count, setCount] = useState(0);

使用es6解构赋值,useState(0)的意思是给count赋予初始值0
count是一个状态值,setCount是给这个状态值进行更新的函数

如果不解构的话,上面的代码得写成这样⬇️

let _useState = useState(0);
let count = _useState[0];
let setCount = _useState[1];
 return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

在这里使用count 可以直接用,我们不需要写成{this.state.count}这样了。
当用户点击按钮时,我们调用setCount函数,这个函数接收的参数是修改过的新状态值。接下来的事情就交给react了,react将会重新渲染我们的Example组件,并且使用的是更新后的新的状态。

关于useState多次调用

首先,useState是可以多次调用的,所以我们完全可以这样写:

function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
}

这个时候 useState根据调用的顺序执行

  const [age, setAge] = useState(42);

这一句由两次渲染组成:
1.给age赋值为42
2.读取age(这时候传的参数42直接被忽略)

所以上面的多次调用可以变成这样:

 //第一次渲染  
useState(42);  //将age初始化为42  
useState('banana');  //将fruit初始化为banana  
useState([{ text: 'Learn Hooks' }]); //...   

//第二次渲染  
useState(42);  //读取状态变量age的值(这时候传的参数42直接被忽略)  
useState('banana');  //读取状态变量fruit的值(这时候传的参数banana直接被忽略)
useState([{ text: 'Learn Hooks' }]); //...

这也就是为什么useState中不能使用if-else语句的原因了
使用使用if后 赋值和读取 可能会产生一个错位,导致程序错误
例如

let showFruit = true;
function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  
  if(showFruit) {
    const [fruit, setFruit] = useState('banana');
    showFruit = false;
  }
 
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

渲染结果会变成⬇️

  //第一次渲染
  useState(42);  //将age初始化为42
  useState('banana');  //将fruit初始化为banana
  useState([{ text: 'Learn Hooks' }]); //...

  //第二次渲染
  useState(42);  //读取状态变量age的值(这时候传的参数42直接被忽略)
  // useState('banana');  
  useState([{ text: 'Learn Hooks' }]); //读取到的却是状态变量fruit的值,导致报错

react规定我们必须把hooks写在函数的最外层,不能写在if-else等条件语句当中,来确保hooks的执行顺序一致。

踩坑知识点

1. useState的初始值,只在第一次有效

下面代码里的data就不能动态赋值给name

const Child = memo(({data}) =>{
    console.log('child render...', data)
    const [name, setName] = useState(data)
    return (
        <div>
            <div>child</div>
            <div>{name} --- {data}</div>
        </div>
    );
})

const Hook =()=>{
    console.log('Hook render...')
    const [count, setCount] = useState(0)
    const [name, setName] = useState('rose')

    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <button onClick={()=>setName('jack')}>update name </button>
            <Child data={name}/>
        </div>
    )
}

总结

React 假设当你多次调用 useState 的时候,你能保证每次渲染时它们的调用顺序是不变的。
通过在函数组件里调用它来给组件添加一些内部 state,React会在重复渲染时保留这个 state
useState 唯一的参数就是初始 state
useState 会返回一个数组:一个 state,一个更新 state 的函数

  • 在初始化渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同
  • 你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并,而是直接替换**

你可能感兴趣的:(react,前端)