React中Hook的简单使用

        Hook是什么?官方文档写的晦涩难懂。Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook是用于函数组件的,因为函数组件没有生命周期,也是无状态组件,所以我们不能和类组件一样用构造函数里面的state和setState。但是,我们可以用内置Hook来复用不同组件之间的状态逻辑。

        先来说说第一个内置hook——State Hook。

1.State Hook

        一句话概括:this.state的代替品。

        我们用一个简单的计算器来加深理解。代码如下:

import React,{useState} from 'react';

function HuckUseState(props) {
    // 取常量是为了避免用户修改 函数名一般是常量名前面加个set 
    const [count,setCount] = useState(0)
    return (
        <div>
            <button onClick={()=>setCount(count+1)}>+</button>
            {count}
            <button onClick={()=>setCount((prev)=>prev-1)}>-</button>
        </div>
    );
}

export default HuckUseState;

        (在app.js中import引入即可查看效果,哈哈哈是HockUseState我写错成Huck)

        

        

我们通过在函数组件里调用它来给组件添加一些内部 state,useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。

     useState 唯一的参数就是初始 state。在上面的例子中,我们的计数器是从零开始的,所以初始 state 就是 0。但useState里面除了放单个的值,还可以放对象:

      const [student,setStudent] = useState({

             name:'liu'

             age:10

     })

  还可以放字符串:

      const [fruit,setFruit] = useState('banana')

 下面是另一个例子,很相似,也是修改咱们学生的年龄,代码如下:

~~~~~1

import React,{useState} from 'react';

function HuckUseState2(props) {
    const [student,setStudent] = useState({
        name:'liu',
        age:10
    })
    return (
        <div>   
            <button onClick={()=>setStudent({...student,age:student.age+1})}>+</button>
            {student.age}
            <button onClick={()=>setStudent({...student,age:student.age-1})}>-</button>
        </div>
    );
}

export default HuckUseState2;

        效果和上面一样~只是在setStudent这个函数中,因为useState中传递的是对象,所以我们得把student解构出来。

2.useEffect

        一句话概括:componentDidMount 和 componentDidUpdate 的代替品。

        可以看最做是class组件中的componentDidMount(挂载后)、componentDidUpdate(更新后)和componentWillUnmount(卸载前)几个生命周期的大集合。给函数组件增加了操作副作用的能力(网络请求、更新Dom、事件的监听)

        useEffect接受两个参数,第一个参数是一个callback,可以用来做一些副作用比如异步请求,修改外部参数等操作。

        如果在callback函数中return了一个函数,这个函数会在组件卸载前执行,需要清除上次订阅的内容可以在这里面写。它会在调用一个新的effect之前对前一个effect进行清理,所以effect的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件时候执行一次。

        当然要记住,在react中我们的副作用分为无需清除的需要清除的。简单来说副作用就是你的函数除了返回你需要的东西之外,还另外进行了其他的操作。而纯函数只返回你需要的数据。

        下面我们来看代码,这段代码基于上文进行修改,我们为计数器增加了一个小功能:将 document 的 title 设置为包含了点击次数的消息。

1)如果只有一个参数callback

        很明显,如果这个时候没有return,你一直点击按钮出现的就是下图的效果:

 咱们再看看加上return后,return何时执行:

~~~~~2

import React, { useState, useEffect } from 'react';
export default function HookUseEffect() {
  const [count, setCount] = useState(0);
  useEffect(() => {
      // 这是模板字符串 ``
    console.log(`You clicked ${count} times`)
    document.title = `You clicked ${count} times`;
    // 副作用消失时候执行 不一定是卸载
    return ()=>{
      console.log('取消订阅')
    }
  });

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

(未点击时效果)

                                               (点击一次效果)

                 可以看出加了return后,之后每次点击【Click me】时候,先取消了订阅再出现【You clicked X times】,return是副作用消失时候执行(不一定是卸载)。

                                                                

        对比一下,使用 class 的示例:

        在 React 的 class 组件中,render 函数是不应该有任何副作用的。一般来说,在这里执行操作太早了,我们基本上都希望在 React 更新 DOM 之后才执行我们的操作。
        这就是为什么在 React class 中,我们把副作用操作到 componentDidMount 和 componentDidUpdate 函数中。但是如果于要写这也太麻烦了!

        

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

        这是一个 React 计数器的 class 组件。它在 React 对 DOM 进行操作之后,立即更新了 document 的 title 属性。注意,在这个 class 中,我们需要在两个生命周期函数中编写重复的代码。(因为我们需要 组件在加载和更新时执行同样的操作)

2)第二个参数source是一个触发条件

        是数组类型,如果数组中的值变化才会触发useEffect的callback回调。

       1.没有传入该参数时,默认在每次render时都会重新执行回调。(如果有个return,那么就是第一次渲染:订阅,第二次:取消订阅,订阅)

        2.传递一个[],只有在组件初始化或者销毁时才会触发。

        3.传入[source],在依赖state发生改变时,才重新执行回调。

        当传递一个[ ]时候是什么效果呢? 

        这个时候还是需要用到咱们的路由的(别忘记下载哦!npm i react-router-dom@5.3)。

        咱们写个简单的路由来看看效果,下图就是用路由来实现两个函数组件的切换。点击state和effect会切换到不同的组件。

         

        两个组件代码为上文有提醒的:~~~~~1和~~~~~2

        注意!~~~~~2 中的代码要加参数 [ ]

        

 

        App.js的代码为:

        

import './App.css';
import MyContext from './MyContext'
import Child from './Child';
import HookUseReducer from './HookUseReducer';
import myReducer from './StudentReducer'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'
import HookUseEffect from './HookUseEffect';
import HookUseState from './HookUseState';

function App() {
  return (
    <div className="App">
      <Router>
        <div>
          <Link to='/state'>state</Link>
          <br/>
          <Link to='/effect'>effect</Link>
        </div>
        <Route path="/state" component={HookUseState}></Route>
        <Route path='/effect' component={HookUseEffect}></Route>
      </Router>
    </div>
  );
}

export default App;

        1)我们先点state

        

         2)再点effect

        

 

        3)再切换到state

 

        组件销毁时才调用

        补充:避免在useEffect中做太多事情,如果有多个依赖可能发生变化时,会按照先后顺序执行。

而且也要避免死循环!(因为getDep每次都返回一个新对象,相当于[source]一直在更新)

 还可以用社区的深度比较来解决。        

 3.useLayoutEffect

        一句话概括,有闪烁情况时用这个hook。

        和useEffect函数签名一致,是在Dom修改后同步触发,而且总是比useEffect先执行,会阻塞浏览器的渲染。

        useEffect执行顺序:组件更新挂载完成=》浏览器dom绘制完成=》执行useEffect回调

        useLayoutEffect执行顺序:组件更新挂载完成=》执行useLayoutEffect回调=》浏览器dom绘制完成

4.useContext

        一句话概括,用于多层级的组件通信(传值)的。

        直接说用法:

5.useReducer

        一句话概括,用于状态管理。相当于简单的redux的使用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值