重生之我又来学React了Day04-- React Hook 🪝

99 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

使用React Hook可以帮助你更好的复用状态逻辑,可以让组件中相关联的部分拆成更小的函数,可以在class这个限制外使用更多的React特性。

今天我们就来学习一些常用的React Hook是如何使用的。

image.png

useState

在useState出现之前,只有类组件被称为状态组件,而函数组件被称为无状态组件。useState的出现 让函数组件也可以拥有状态。 useState返回两个值,第一个是数据,第二个是改变数据的方法

import { useState } from "react";
export default function Example() {
  // 声明一个叫 "count" 的 state 变量 初始值为 0
  const [count, setCount] = useState(0);
  // 设置一个person对象 初始值为 {name: "rose"}
  const [person, setPerson] = useState({ name: "rose" });
  return (
    <div>
      <p>You clicked {count} times</p>
      <p>{person.name}</p>
      <p>{person.age}</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <button onClick={() => setPerson({ ...person, age: "321" })}>
        设置age
      </button>
    </div>
  );
}

useEffect

有时候我们想在React更新DOM之后做一些其他的操作。可以通过useEffect方法,传递一个effect方法该方法在DOM更新中之后调用。effect方法默认在每次DOM更新(第一次渲染和每次更新)之后都会执行。


import { useState, useEffect } from "react";

export default function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log(`You clicked ${count} times`);
  });
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

image.png

点击按钮会触发useEffect里的effect方法。

可以在effect方法里面返回一个清除方法,当要执行下一次effect函数的时候会先执行上一次的effect清除方法。


import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log(`1effect`);
    return () => {
      console.log("destoryed1");
    };
  });
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount(count - 1)}>-1</button>
    </div>
  );
}

image.png

⬆️点击按钮之后会执行上一次effect方法返回的函数。

给useEffct的传入第二个参数(一个数组),可以根据数组里面数据的变化来执行effect方法。


import { useState, useEffect } from "react";

export default function Example() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("🚀");
  useEffect(() => {
    console.log(`1effect`);
  }, [name]); // 只有修改name 会触发effect
  return (
    <div>
      {name}
      {count}
      {/* 不会触发effect */}
      <button onClick={() => setCount(count + 1)}>+1</button>
      {/* 会触发effect */}
      <button onClick={() => setName("🔩")}>变🔩</button>
    </div>
  );
}

当给第二个参数传递一个空数组的时候,该effect方法只会在第一次渲染的时候执行

import { useState, useEffect } from "react";

export default function Example() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("🚀");
  useEffect(() => {
    console.log(`1effect`);
  }, []);
  return (
    <div>
      {name}
      {count}
      {/* {count > 1 ? <Son></Son> : <Daughter></Daughter>} */}
      {/* 这两个按钮点击 都不会再触发effect了*/}
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setName("🔩")}>变🔩</button>
    </div>
  );
}

useLayoutEffect

useEffect是异步执行的,而useLayoutEffect是同步执行的,用法都是一样的。

import { useState, useEffect, useLayoutEffect } from "react";

export default function Example() {
  const [count, setCount] = useState(1);
  // 会出现闪烁的效果
  useEffect(() => {
    if (count === 0) {
      setCount(10 + Math.random() * 2000);
    }
  }, [count]);
  // 不会出现闪烁的效果
  // useLayoutEffect(() => {
  //   if (count === 0) {
  //     setCount(10 + Math.random() * 2000);
  //   }
  // }, [count]);
  return (
    <div>
      count:{count}
      <button onClick={() => setCount(0)}>置为0</button>
    </div>
  );
}

useContext

我们之前有学过React.createContext得到的Provicer和Consumer来实现跨级组件的数据传递。useContext则是实现Consumer的React Hooks用法。

import Test from "./Test";
import React from "react";
export const Con = React.createContext(null);
export default function App() {
  return (
    <div>
      <Con.Provider value={{ name: "rose" }}>
        <Test></Test>
      </Con.Provider>
    </div>
  );
}

import { useContext } from "react";
import { Con } from "./App";
export default function Test() {
  const con = useContext(Con); // 获取到Provider的值
  return <div>子组件接受context {con.name}</div>; 
}

image.png

useRef

day02文章中,我们有接触到过useRef。此处不再讨论。

useMemo

useMemo是将某个函数返回值“放入到react底层原型链上,并返回该返回值的索引。该Hook主要是减少组件重新渲染时不必要的更新操作。useMemo的第二个参数是一个依赖项的数组,如果依赖项未发生改变,则直接使用保存在原型链上面的值,以此提高组件的性能。

import React from "react";
import { useMemo, useState } from "react";
export default function App() {
  const [num, setNum] = useState(0);
  const [age, setAge] = useState(100);
  const total_sum = useMemo(() => {
    console.log("memo");
    let total = 0;
    for (let i = 0; i < 1000; i++) {
      total += i;
    }
    return total;
  }, [num]);
  return (
    <div>
      total_sum: {total_sum}
      {/* 点击按钮组件会更新 useMemo会执行,因为依赖项num被修改了 */}
      <button onClick={() => setNum(num + 1)}>num+1</button> 
      {/* 点击按钮组件会更新  但useMemo不会执行,因为依赖项num没被修改 */}
      <button onClick={() => setAge(age + 1)}>age+1</button>
    </div>
  );
}

和React-redux相关的常用Hooks

useSelector

从redux的store当中获取到state

import React from 'react'
import { useSelector } from 'react-redux'

export const App = () => {
  // 获取到state里面的theme属性
  const theme = useSelector(state => state.theme)
  return <div>{theme}</div>
}

useDispatch

执行store里面的action方法

import React from 'react'
import { useDispatch } from 'react-redux'

const dispatch = useDispatch()
export const App = () => {

  // 获取到state里面的theme属性
  function changeTheme(color) {
   // 执行store里面名为changeTheme的action
      dispatch({ type:'changeTheme',payload:{ color } })
  }
  return <div>
      <button onClick={changeTheme('red')}>修改theme为red</button>
  </div>
}

和React-router(v6)相关的常用Hooks

useNavigate

实现路由跳转

import {useNavigate} from 'react-router-dom'
const navigate = useNavigate();
navigate('/login') // 跳转到login页面

navigate(1) // 前进一页
navigate(-1) // 后退一页

useParams

useParams获取路由的param参数

  import { useParams } from "react-router-dom";

  export default function ArticleDetail() {
    let params = useParams();
    // 获取文章id
    return <h2>User: {params.id}</h2>;
  }

useSearchParams

获取URL?后面的搜索(也就是query)参数

import { useSearchParams } from "react-router-dom";
export default function UserDetail() {
  let [searchParams, setSearchParams] = useSearchParams();
  // setSearchParams({"id":2}) 也可以这样设置url搜索参数-> 得到:http://URL/article?id=2
  return <h2>User: {searchParams.id}</h2>; // 获取到搜索参数里面id的值
}

使用Hook的注意事项

  • 只在React函数中调用Hook,比如React的函数组件中,自定义Hook中调用其他的Hook
  • Hook需要在组件的最顶层调用