React Hook--useState

183 阅读4分钟

Hook

React Hook就是一些React提供的内置函数,这些函数可以让函数组件和类组件一样能够拥有组件状态(state)以及进行副作用。但是不要什么业务都使用Hook请在合适的时候使用Hook,否则会造成性能问题。(能不用的时候就不用,当遇到性能不好优化的时候,自然会想到使用它)

useState

useState和类组件的this.state一样,都是用来管理组件状态的。在React Hook没出来之前,函数组件也叫做Functional Stateless Component(FSC:功能无状态的组件),这是因为函数组件每次执行的时候都会重新运行整个函数生成新的函数作用域所以同一个组件的不同渲染(render)之间是不能够共用状态的。 而类组件是重新运行render函数,组件状态并不会重新创建。

useState它允许函数组件将自己的状态持久化到React运行时的某个地方,这样在组件每次重新渲染的时候都可以从这个地方拿到该状态,而且当该状态被更新的时候,组件也会重渲染。

useState使用的语法

import React from 'react'

export default function App() {
  let msg='hello,react';
  let change=()=>{
    msg='golden stars';
  };
  let look=function(){
    console.log(msg);
  }
  return (
    <div>
      <p>{msg}</p>
      <button onClick={change}>change</button>
      <button onClick={look}>look</button>
    </div>
  )
}

2.gif

变量的数据更新了,但是页面并没有刷新。

useState函数返回值是一个数组,数组中第1个元素是当前state的最新值,第二个元素是一个用来更新state的函数,函数传入的值就是要修改的数据,而且调用该函数会刷新页面中使用过取下标0的模板。

import {useState} from 'react'

export default function App() {
  let msg=useState('hello,react');
  let change=()=>{
    msg[0]=msg[1]('golden stars');
  };
  let look=function(){
    console.log(msg);
  }
  return (
    <div>
      <p>{msg[0]}</p>
      <button onClick={change}>change</button>
      <button onClick={look}>look</button>
    </div>
  )
}

2.gif

我们可以通过解构赋值来创建变量,效果同理。

import {useState} from 'react'

export default function App() {
  let [msg,setMsg]=useState('hello,react');
  let change=()=>{
    msg=setMsg('golden stars');
  };
  let look=function(){
    console.log(msg);
  }
  return (
    <div>
      <p>{msg}</p>
      <button onClick={change}>change</button>
      <button onClick={look}>look</button>
    </div>
  )
}

2.gif

msg和setMsg这两个变量的命名是自己定义的 msg可用于组件内部使用的数据,setMsg函数用于修改msg,当修改后会触发所有使用过msg的地方重新取值(调用render) 一个函数组件中可以用多个useState

useState返回数组中第2个元素用于修改状态的函数是全量替代。 全量替代就是传入的数据会把原来的数据全部替换。 类组件的浅归并是传入的数据原来有就会更新,原来没有的数据就会创建该数据。

import {useState} from 'react'

export default function App() {
  let [obj,setObj]=useState({msg:'hello',info:'minus'});
  let change=()=>{
    obj=setObj({msg:'golden stars'});
  };
  let look=function(){
    console.log(obj);
  }
  return (
    <div>
      <p>{obj.msg}</p>
      <p>{obj.info}</p>
      <button onClick={change}>change</button>
      <button onClick={look}>look</button>
    </div>
  )
}

2.gif

传入对象会把原来的覆盖,传入的对象中没有info属性,取属性值就是undefined,undefined不会在页面渲染。

解决方法:解构赋值后useState返回的对象是一个具有响应式的对象并不是原来传入的那个普通对象,如果直接传入响应式对象是不会刷新页面的。

先取出对象的属性值修改之后再使用对象扩展符取出所有属性再传入这样传入的就是一个新的普通对象就可以刷新页面
import {useState} from 'react'

export default function App() {
  let [obj,setObj]=useState({msg:'hello',info:'minus'});
  let change=()=>{
    obj.msg='golden stars';
    obj=setObj({...obj});
    // {...obj}大括号在js语法中就是创建对象的直接量,此处就是传入了一个装有响应式对象的所有成员的新对象
  };
  let look=function(){
    console.log(obj);
  }
  return (
    <div>
      <p>{obj.msg}</p>
      <p>{obj.info}</p>
      <button onClick={change}>change</button>
      <button onClick={look}>look</button>
    </div>
  )
}

2.gif

useState返回的修改状态的函数没有回调函数

无论是useState还是类组件的this.setState都可能是异步调用的,也就是说每次组件调用完之后都不能立即拿到最新的state值。

为了解决这个问题,类组件的this.setState允许通过一个回调函数来获取到最新的state值:

this.setState(newState, state => { console.log( state)})

函数组件的setState函数不存在这么一个可以拿到最新state的回调函数,不过我们可以使用useEffect来实现相同的效果。