React——hook之useState,useEffect精讲

hook是什么?

函数式组件+hook

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。

React 内置了一些像 useState 这样的 Hook。你也可以创建你自己的 Hook 来复用不同组件之间的状态逻辑。

一,State Hook

先看一下使用代码:实现一个基本的计数器

  • 第一行: 引入 React 中的 useState Hook。它让我们在函数组件中存储内部 state。
  • 第三行: 在 App组件内部,我们通过调用 useState Hook 声明了一个新的 state 变量。它返回一对值给到我们命名的变量上。我们把变量命名为 count,因为它存储的是点击次数。我们通过传 0 作为 useState 唯一的参数来将其初始化为 0。第二个返回的值本身就是一个函数。它让我们可以更新 count 的值,所以我们叫它 setCount
  • 第七行: 当用户点击按钮后,我们传递一个新的值给 setCount。React 会重新渲染 App 组件,并把最新的 count 传给它。
import React,{useState} from 'react'
function App(){  
  //声明一个叫count的state变量
  // 使用数组解构的语法,让我们在调用userState的时候给state变量取不同的名字
  const [count,setCount]=useState(12)
    return(
      <>
    <p>{count}</p>
    <button onClick={()=>setCount(count+1)}>点我一下</button>
      </>
    )
  }

export default App

 通俗的讲:组件的更新分为两个过程

首次渲染时,组件内部代码会被执行一次,其中useState也会被执行,重点注意:初始值只有在首次渲染时生效

更新渲染:setcount也会更新,

1.组件App会再次渲染,这个函数会再次执行

2.useState再次执行时,得到的新的count不是0而是新修改的1,模板会用新值渲染

注意:不能写count++或count--;写成count+1;或者count-1 

在调用useState()时都做了什么?

它定义一个 “state 变量”。我们的变量叫 count, 但是我们可以叫他任何名字,比如 banana。这是一种在函数调用时保存变量的方式 —— useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留

useState 需要哪些参数?

useState() 方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字或字符串对其进行赋值,而不一定是对象。在示例中,只需使用数字来记录用户点击次数,所以我们传了 0 作为变量的初始 state。(如果我们想要在 state 中存储两个不同的变量,只需调用 useState() 两次即可。)

useState 方法的返回值是什么? 

返回值为:当前 state 以及更新 state 的函数。这就是我们写 const [count, setCount] = useState() 的原因。这与 class 里面 this.state.count 和 this.setState 类似,唯一区别就是你需要成对的获取它们。 

 方括号有什么用?

这种 JavaScript 语法叫数组解构。它意味着我们同时创建了 count 和 setCount 两个变量,count 的值为 useState 返回的第一个值,setCount 是返回的第二个值。它等价于下面的代码:

 var fruitStateVariable = useState('banana'); // 返回一个有两个元素的数组
  var fruit = fruitStateVariable[0]; // 数组里的第一个值
  var setFruit = fruitStateVariable[1]; // 数组里的第二个值

 当我们使用 useState 定义 state 变量时候,它返回一个有两个值的数组。第一个值是当前的    state,第二个值是更新 state 的函数。使用 [0] 和 [1] 来访问

注意:数组中名字可以改变,顺序不可以改变

二,useEffect

1.基本使用

Effect Hook 可以让你在函数组件中执行副作用操作

那么什么是副作用呢?

数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。

先看一段基本使用的代码

点击计数器,在title标签栏同步显示计数结果

import React,{useState,useEffect} from 'react'

function App(){
  const [count,setCount]=useState(1)
  useEffect(()=>{
    document.title=count
  })
  return(
    <>
    
    <p>{count}</p>
    <button onClick={()=>setCount(count+1)}>点我一下</button>
    </>
  )
   
  
}

export default App

如果你看懂了上面代码,熟悉生命周期函数的话就会发现

useEffect Hook 看做 componentDidMountcomponentDidUpdate 和 componentWillUnmount 这三个函数的组合。


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

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

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

注意:这样我们就要在两个生命周期中写同样的代码,就算封装成函数,也得调用两次

                             这个时候你回过头看看最初使用useEffect的代码

2.依赖特定项

在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。

给userEffect(),传入第二个参数,特定数据进行调用

 如下代码,定义两个计数器使用第一个进行特定依赖传入,第二个不传入

import React,{useState,useEffect} from 'react'
function App(){
  const [count,setCount]=useState(1)
  const [count1,setCount1]=useState(1)
  useEffect(()=>{
    console.log('我更新了');
    
    document.title=count
  },[count])
  return(
    <>
    <p>{count}</p>
    <p>{count1}</p>
    <button onClick={()=>setCount(count+1)}>监听依赖点击</button>
    <button onClick={()=>setCount1(count1+1)}>普通点击</button>
    </>
  )  
}
export default App

 当我们点击第一个按钮时,可以看到调用了useEffect()

 当我们点击第二个按钮时,虽然值更新了,但是没有调用useEffect 

 注意事项:凡是在useEffect中用到的数据,都应该在第二次参数进行说明,否则可能会有bug

 总结一下:

1.不加依赖项:初始化  ,更新时都会重新渲染

2.加【】,初始化执行一次  发送网络请求用这个

3.加特定依赖项【count,name】-首次执行+数据变化时执行

发送网络请求

错误演示  

不可以直接在useEffect的回调函数外层直接包裹 await ,因为异步会导致清理函数无法立即返回

useEffect(async ()=>{    
    const res = await axios.get('http://geek.itheima.net/v1_0/channels')   
    console.log(res)
},[])

 正确演示  在内部单独定义一个函数,然后把这个函数包装成同步

useEffect(()=>{   
    async function fetchData(){      
       const res = await axios.get('http://geek.itheima.net/v1_0/channels')                            console.log(res)   
    } 
},[])

3.清理副作用

添加清理副作用函数后:一旦组件被销毁,定时器也被清理

import { useEffect, useState } from 'react'

function Foo() {  
    useEffect(() => {   
        const timerId = setInterval(() => {      
            console.log('副作用函数执行了')    
        }, 1000)   
        // 添加清理副租用函数    
        return () => {      
            clearInterval(timerId)    
        }  
    })  
    return <div>Foo</div>
}
function App() {  
    const [flag, setFlag] = useState(true)  
    return (   
        <>      
          <button onClick={() => setFlag(false)}>click</button>      
         {flag ? <Foo/> : null}    
        </>    
    )
}
export default App

 4,深入了解

userEffect做了什么?

你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。

userEffect都会在每次渲染之后执行吗?

默认情况下,它在第一次渲染之后每次更新之后都会执行。

为什么在组件内部调用 useEffect

将 useEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。

三.hook使用规则 

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.指尖舞者

如果帮助到了你,请给点赞助支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值