react----hook(1)

react hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

为什么需要hook?

  1. 在组件之间复用状态逻辑很难,providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。而Hook 使你在无需修改组件结构的情况下复用状态逻辑。
  2. 每个生命周期常常包含一些不相关的逻辑,相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。如此很容易产生 bug,并且导致逻辑不一致。在多数情况下,不可能将组件拆分为更小的粒度,因为状态逻辑无处不在。Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据)
  3. class 是学习 React 的一大屏障。你必须去理解 JavaScript 中 this 的工作方式,这些代码非常冗余,Hook 使你在非 class 的情况下可以使用更多的 React 特性

ps:react团队将继续为 class 组件提供支持 Hook 是向下兼容的

在 Facebook,我们有成千上万的组件用 class 书写,我们完全没有重写它们的计划。相反,我们开始在新的代码中同时使用 Hook 和 class。

hook是什么?

  1. Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数
  2. Hook 就是 JavaScript 函数

hook使用规则

  1. 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  2. 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用
  3. 自定义的 Hook 中也可以调用hook
hook简介
1useState声明一个新的 state 变量,通过在函数组件里调用它来给组件添加一些内部 state
2useEffect给函数组件增加了操作副作用的能力 (数据获取、订阅或者手动修改过 DOM称为“副作用”,或者简称为“作用”)
3自定义hook组件之间重用一些状态逻辑,自定义 Hook 可以让你在不增加组件的情况下达到同样的目的
4useContext帮助我们跨越组件层级直接传递变量,useContext 接收上下文变量,实现共享
5useCallback在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行,返回缓存的函数
6useMemo在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行,返回缓存的变量
7useReducerreducer是一个函数(state, action) => newState:接收当前应用的state和触发的动作action,计算并返回最新的state。
8useRefuseRef 返回一个可变的 ref 对象
9useImperativeHandleuseImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值
10useLayoutEffect大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同

一、useState

简介:

  1. 函数组件里调用useState来给组件添加一些内部 state
  2. React 会在重复渲染时保留这个 state
  3. useState 会返回一对值:当前状态一个让你更新它的函数
    1. 你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState
    2. 它不会把新的 state 和旧的 state 进行合并 ,更新 state 变量是替换
  4. useState 只有一个参数,唯一的参数就是初始 state 相当于设置初始值
  5. 可以在一个组件中多次使用 State Hook ,声名多个state变量

PS:

1.	**useState 返回一个有两个元素的数组** (重点: 数组  第一元素-当前state  第二元素-更新该state的函数)

2.	**[数组解构](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring)的语法让我们在调用 `useState` 时可以给 state 变量取不同的名字**

对比 :

读取state
在 class 中在函数中
this.state.count 读取直接用 count
<p>You clicked {this.state.count} times</p><p>You clicked {count} times</p>
更新 State
在class中在函数中
调用 this.setState()更新 countsetCount() 更新count值
<button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button><button onClick={() => setCount(count + 1)}> Click me </button>

运用:

 1:  import React, { useState } from 'react';
 2:
 3:  function Example() {
 4:    const [count, setCount] = useState(0);
 5:
 6:    return (
 7:      <div>
 8:        <p>You clicked {count} times</p>
 9:        <button onClick={() => setCount(count + 1)}>
10:         Click me
11:        </button>
12:      </div>
13:    );
14:  }
  • 第一行: 引入 React 中的 useState Hook。它让我们在函数组件中存储内部 state。
  • 第四行:Example 组件内部,我们通过调用 useState Hook 声明了一个新的 state 变量。它返回一对值给到我们命名的变量上。我们把变量命名为 count,因为它存储的是点击次数。我们通过传 0 作为 useState 唯一的参数来将其初始化为 0。第二个返回的值本身就是一个函数。它让我们可以更新 count 的值,所以我们叫它 setCount
  • 第九行: 当用户点击按钮后,我们传递一个新的值给 setCount。React 会重新渲染 Example 组件,并把最新的 count 传给它。

二、useEffect

简介:

  1. 给函数组件增加了操作副作用的能力
  2. 它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API
  3. 副作用函数是在组件内声明的,它们可以访问到组件的 props 和 state
  4. React 会在每次渲染后调用副作用函数 包括第一次渲染的时候
  5. 副作用函数还可以通过返回一个函数来指定如何“清除”副作用 ?
  6. 可以在一个组件中多次使用 Effect Hook
  7. 默认情况下,useEffect 会在每次渲染后都执行
  8. useEffect 可以在组件渲染后实现各种不同的副作用。有些副作用可能需要清除,所以需要返回一个函数
  9. **Hook 允许我们按照代码的用途分离他们,**React 将按照 effect 声明的顺序依次调用组件中的每一个 effect

PS:

  1. 如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可
  2. React 会跳过这个 effect,这就实现了性能的优化。
  3. 如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数
    (这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行)
  4. React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect,因此会使得额外操作很方便

对比:

在class中在函数中
1.很多情况下,我们希望在组件加载和更新时执行同样的操作,从概念上说,我们希望它在每次渲染之后执行
2.React 的 class 组件没有提供这样的方法
3.即使我们提取出一个方法,我们还是要在两个地方调用它
React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它
“渲染之后”发生,不用再去考虑“挂载”还是“更新‘’

运用:

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
}
  • 声明了 count state 变量,并告诉 React 我们需要使用 effect
  • 在 effect 中获取到最新的 count 值,因为他在函数的作用域内
  • 当 React 渲染组件时,会保存已使用的 effect,并在更新完 DOM 后执行它
  • 这个过程在每次渲染时都会发生,包括首次渲染。

三、自定义hook

简介:

  1. 逻辑抽取到自定义 Hook里面,可以在各个组件中使用这个自定义hook
  2. 各个组件的 state 是完全独立的,不复用 state 本身,复用状态逻辑
  3. Hook 的每次调用都有一个完全独立的 state ---- 因此你可以在单个组件中多次调用同一个自定义 Hook。
  4. 函数 函数名以 “use” 开头并调用其他 Hook ==> 自定义 Hook

四、useContext

简介:

  1. const value = useContext(MyContext);接收一个 context 对象(React.createContext 的返回值)
    并返回该 context 的当前值
  2. 当前context 值由上层组件中距离当前组件最近的 <MyContext.Provider>value prop 决定
  3. 需要在上层组件树中使用 <MyContext.Provider> 来为下层组件提供 context
  4. 组件上层最近 <MyContext.Provider> 更新,Hook 会触发重渲染,使用最新context value 值。

运用:

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

五、useCallback

简介:

  1. 在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行,返回缓存的函数

六、useMemo

简介:

  1. 在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行,返回缓存的变量

七、useReducer

简介:

  1. reducer是一个函数(state, action) => newState:接收当前应用的state和触发的动作action,计算并返回最新的state。

八、useRef

简介:

  1. 代码中用useRef创建了xxxx 对象,并将其赋给了buttonref属性。这样,通过访问xxxx.current就可以访问到button对应的DOM对象

运用:

import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />
});

const App = props => {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button
        onClick={() => fancyInputRef.current.focus()}
      >父组件调用子组件的 focus</button>
    </div>
  )
}

ReactDOM.render(<App />, root);

九、useImperativeHandle

简介:

  1. useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。
  2. 在大多数情况下,应当避免使用 ref 这样的命令式代码。
  3. useImperativeHandle 应当与 forwardRef 一起使用

语法:

useImperativeHandle(ref, createHandle, [deps])

运用:

import React, { forwardRef, useImperativeHandle, useEffect, useRef } from 'react'

const TestRef = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    open() {
      //最后结果打印出了open。
      console.log("open")
    }
  }))
})

function App () {
  const ref = useRef()
  useEffect(() => {
    ref.current.open()
  },[])
  
  return(
    <>
      <div>kjs</div>
      <TestRef ref={ref}></TestRef>
    </>
  )
}
export default App

十、useLayoutEffect

简介:

  1. 大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同

tip:

  1. Hook 需要在我们组件的最顶层调用

  2. 如果我们想要有条件地执行一个 effect,可以将判断放到 Hook 的内部

      // 🔴 在条件语句中使用 Hook 违反第一条规则
      if (name !== '') {
        useEffect(function persistForm() {
          localStorage.setItem('formData', name);
        });
      }
    

    ===========》》

      useEffect(function persistForm() {
        // 👍 将条件判断放置在 effect 中
        if (name !== '') {
          localStorage.setItem('formData', name);
        }
      });
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>