React Hooks的基本使用解析

React Hook的基本使用

Hook 是什么? 在中文官网中是这么介绍的:

Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你在 React 函数组件中添加 state 的 Hook。

什么时候我会用 Hook?

如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其它转化为 class。现在你可以在现有的函数组件中使用 Hook。当你想在函数式组件中使用类式组件的生命周期方法时可以使用Hook。

一:useState

在类式组件中我们要在构造函数中声明this.state={count:0}的方式来使用变量count,但在函数式组件中并没有构造函数,所以就可以使用useState Hook来使用变量,使用方式如下:
useState example picture

  • 首先需要在react中引入useState Hook;

    import React,{useState} from 'react'

  • 在函数式组件中初始化,等号左侧中括号中第一个值count为要使用的变量,

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

  • setCount时一个函数,只能调用改函数修改count的值,等号右侧Hook中的参数10为count的初始值;
  • 例子中点击按钮时就会调用setCount函数来修改count的值。

    <button onClick={()=>setCount(count+2)}>点击+2</button>

二:useRef

useRef Hook 经常用在表单元素中,用来获取对表单元素的引用,从而获取对应表单元素的值。使用方式如下:
useRef example picture

  • 同样第一步需要从react中引入useRef Hook

    import React,{useRef} from 'react'

  • 在函数式组件中初始化,null为初始值,可以省略

    const input=useRef(null);

  • 给表单元素的ref属性与useRef初始化的变量建立引用关系

    <input type="text" ref={input} onChange={handleChange} />

  • 在处理函数中获取表单元素的值,current属性可以获取到对应的html节点

    console.log('ref:',input.current.value);

在这个例子中,因为处理函数监听的是调用函数的节点本身(input元素的onChange事件调用了handleChange处理函数),所以在处理函数中会有一个参数event(例子中用e表示),通过event的target属性也可以拿到事件对应的节点,进一步获取值,react在官网中也提醒了大家尽可能少用ref属性。

三:useEffect

在函数式组件中使用useEffect就可以使用类似于类式组件的生命周期方法,具体使用方式如下:
useEffect example picture

  • useEffect的第一个参数是一个回调函数,第二个参数是一个数组,数组为空时表示改Hook只在组件第一次挂载时使用,类似于生命周期方法componentDidMount()
  • 第二个参数数组中是要监听的变量,表示改变量值发生改变时调用第一个回调函数,可以监听多个变量,类似于生命周期方法componentWillUpdate();
  • 第一个参数(回调函数)可以返回一个函数,改函数会在组件卸载时执行,类似于生命周期方法componentWillUnmount();

四:useContext

useContext Hook 可以在多层嵌套的组件之前快速直接的进行参数传递,官网中是如下介绍的:

接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染。

useContext example picture

  • 使用方式如下:

    • 调用React.createContext()方法会生成一个类似于组件的元素,例子中为TaskContext,
    • 用生成的TaskContext.Provider包裹子组件,通过value属性给子组件传值
    • 子组件通过useContext Hook 来接收上层组件传递来的值,例如:let task=useContext(TaskContext)
    • 变量task中就包含了上层组件传递的值,就可以在本组件中使用。

    五: useReducer

useState的另一种选择。接受类型为(state, action) => newState的reducer,并返回与分派方法配对的当前状态。(如果您熟悉Redux,您应该已经知道它是如何工作的).

当你有复杂的状态逻辑,包括多个子值,或者当下一个状态依赖于前一个状态时,useReducer通常比useState更好。useReducer还允许您优化触发深度更新的组件的性能,因为您可以向下传递分派而不是回调.

React保证分派函数标识是稳定的,并且在重新呈现时不会改变。这就是为什么从useEffect或useCallback依赖项列表中省略是安全的。

有两种不同的方法来初始化useReducer状态。您可以根据用例选择其中任何一个。最简单的方法是将初始状态作为第二个参数传递.

还可以惰性地创建初始状态。为此,您可以传递一个init函数作为第三个参数。初始状态将被设置为init(initialArg)。

  • useReducer就是阉割版的redux,实现了redux的一些功能,有时候可以当做redux来使用,但缺少了状态共享的功能,常与useContext搭配使用。
  • useReducer接受三个参数:
    • 第一个为reducer函数,与redux中的reducer使用方法相同
    • 第二个为初始的state值
    • 第三个参数可选,是一个函数,useReducer会把第二个参数(也就是初始的state值)传给改函数作为参数;
  • useReducer的常见使用景为:
    • state不是基本数据类型,而是引用类型时
    • state的变化很复杂时
    • 需要去嵌套很深的子组件中去修改状态时
    • 应用很复杂时,把业务和UI分开

基本使用:

import React, { useReducer } from "react";

const initalState = { count: 0 };

const createIncrementAction = (data) => ({ type: "increment", data });
const createDecrementAction = (data) => ({ type: "decrement", data });

function reducer(state, action) {
  let { type, data } = action;
  let { count } = state;
  switch (type) {
    case "increment":
      return { count: count + data };
    case "decrement":
      return { count: count - data };
    default:
      throw new Error();
  }
}

export default function UseReducer() {
  const [state, dispatch] = useReducer(reducer, initalState);
  return (
    <div>
      <p>Count:{state.count}</p>
      <button onClick={() => dispatch(createIncrementAction(2))}>
        increment 2
      </button>
      &nbsp;
      <button onClick={() => dispatch(createDecrementAction(3))}>
        decrement 3
      </button>
    </div>
  );
}

惰性创建初始state:

import { useReducer } from "react";

const init = (initalCount) => ({ count: initalCount });

function reducer(state, action) {
  let { type, data, payload } = action;
  switch (type) {
    case "increment":
      return { count: state.count + data };
    case "decrement":
      return { count: state.count - data };
    case "reset":
      return init(payload);
    default:
      throw new Error();
  }
}

const createIncrementAction = (data) => ({ type: "increment", data });
const createDecrementAction = (data) => ({ type: "decrement", data });
const createResetAction = (payload) => ({ type: "reset", payload });

export default function Counter({ initialCount = 0 }) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}&nbsp;
      <button onClick={() => dispatch(createResetAction(initialCount))}>
        Reset
      </button>
      &nbsp;
      <button onClick={() => dispatch(createDecrementAction(2))}>-2</button>
      &nbsp;
      <button onClick={() => dispatch(createIncrementAction(3))}>+3</button>
    </>
  );
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值