天天看点

常用React Hooks简单上手

React组件分为类式组件与函数式组件,也成为状态组件与无状态组件,当你的组件需要状态对象时,大多数的写法都是Class,它有this、有生命周期、而function既没有自己的this,也没有生命周期。如何使用function来编写有状态、有生命周期的组件呢,那么就要介绍React

16.8版本后退出的新特性——Hooks

React Hooks

  • useState(状态)
  • useRef(Ref)
  • useEffect(副作用)
  • useContext(上下文)
  • useReducer(Redux)
  • 自定义Hook

useState

useState钩子可以创建一个状态对象以及设置状态对象的方法,用法如下:

其中

useState(initState, setState)

接收两个参数,第一个参数

initState

为初始化状态数据,第二个参数

setState

为设置状态的方法,一般第一个参数需要设置,如果不设置count则为undefined。

例子:

import { useState } from "react";
import "./styles.css";
export default function App() {
  const [count, setCount] = useState(0);

  const add = () => {
    setCount(count + 1);
  };

  return (
    <div className="App">
      <h1>我是父组件</h1>
      <p>Count: {count}</p>
      <button onClick={add}>加1</button>
    </div>
  );
}
           

这里由useState创建出的count类似于Class组件中state中创建的对象,而setCount与Class组件中的setState相似(都可以传递一个值或者一个函数)

useRef

useRef用于创建一个ref对象,可以在必要的时候在ref对象中

current

中读取该ref的值,用法如下:

同样

useRef(initRef)

也可以传递一个参数,相当于给ref的

current

创建一个默认值

例子:

import { useState, useRef } from "react";
import "./styles.css";
export default function App() {
  const [count, setCount] = useState(0);
  const InputRef = useRef();
  const add = () => {
    setCount(count + InputRef.current.value * 1);
  };
  return (
    <div className="App">
      <h1>我是父组件</h1>
      <p>Count: {count}</p>
      <input ref={InputRef} />
      <button onClick={add}>求和</button>
    </div>
  );
}
           

useEffect

开篇说了function组件没有自己的状态与生命周期,通过

useState

可以创建状态对象,而使用

useEffect

可以模拟生命周期,例如Class组件中的

componentDidMount

componentDidUpdate

componentWillUnMount

生命周期。

useEffect接受两个参数,可以通过传递不同的参数来模拟上述的生命周期

模拟

componentDidMount

例子:

import { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
  const [count, setCount] = useState(0);
  const add = () => {
    setCount(count + 1);
  };
  useEffect(() => {
    console.log("useEffect,count:",count);
  },[]);
  return (
    <div className="App">
      {console.log("render, count:",count)}
      <h1>我是父组件</h1>
      <p>Count: {count}</p>
      <button onClick={add}>求和</button>
    </div>
  );
}
           
常用React Hooks简单上手

当组件第一次渲染后,可以在控制台看到,

useEffect

在组件挂载后执行,此时和Class组件中的

componentDidMount

作用是一样的。

常用React Hooks简单上手

当你再次点击后,你会发现,只有组件被更新了,而

useEffect

不输出了

模拟

componentDidUpdate

例子:

import { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
  const [count, setCount] = useState(0);
  const [Name, setName] = useState("法外狂徒");
  const add = () => {
    setCount(count + 1);
  };
  const changeName = () => {
    setName((preName) => preName === "法外狂徒" ? "张三" : "法外狂徒")
  }
  useEffect(() => {
    console.log(`useEffect,count:${count}, Name:${Name}`);
  }, [count]);
  return (
    <div className="App">
      {console.log(`render,count:${count}, Name:${Name}`)}
      <h1>我是父组件</h1>
      <p>Name: {Name}</p>
      <p>Count: {count}</p>
      <button onClick={add}>求和</button>
      <button onClick={changeName}>换名</button>
    </div>
  );
}
           
常用React Hooks简单上手

此时,点组件挂载后,分别点击求和按钮与换名按钮后会发现,点击求和后useEffect会输出,状态也发生了改变,而点击换名按钮后,虽然状态发生了改变,但是useEffect却没有输出。因为在useEffect中传递的第二个参数中,只对

count

进行了更新的监听(有点Vue中的Watch内味了吗),当

count

状态更新后,会执行传递的方法,而其他状态更新就不会执行。

模拟

componentWillUnMount

例子:

import { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
  const [flag, setFlag] = useState(true);
  const switchComponent = () => {
    setFlag(!flag);
  };

  useEffect(() => {
    console.log(`useEffect App`);
    return () => {
      console.log("Component unMount");
    };
  }, []);
  return (
    <div className="App">
      {console.log(`render`)}
      <h1>我是父组件</h1>
      <button onClick={switchComponent}>切换</button>
      {flag ? <A /> : <B />}
    </div>
  );
}

function A() {
  useEffect(() => {
    console.log(`useEffect >>> A`);
    return () => {
      console.log("A Component unMount");
    };
  }, []);
  return <div>我是A组件</div>;
}
function B() {
  useEffect(() => {
    console.log(`useEffect >>> B`);
    return () => {
      console.log("B Component unMount");
    };
  }, []);
  return <div>我是B组件</div>;
}

           

上述例子中,模拟了一个组件加载与卸载的效果,点击切换按钮可以将A组件与B组件来回挂载到页面中。

常用React Hooks简单上手

当第一次页面渲染时,父组件和子组件的

useEffect

都会被执行,和Classs组件的生命周期相同。

第一次点击切换按钮,A组件卸载,B组件挂载

常用React Hooks简单上手

这时候可以发现,A组件卸载的时候,执行了

useEffect

返回的方法,而这个方法正是模拟了Class组件中的

componentWillUnMount

生命周期。

第二次点击切换按钮,B组件卸载,A组件挂载

常用React Hooks简单上手

可以通过这个方法来在function组件模拟

componentWillUnMount

useContext

在Class组件中,组件实例对象中有一个

context

属性用于隔层传递数据,在function组件中,可以使用

useContext

来进行创建

context

例子:

import { useState, useContext, createContext } from "react";
import "./styles.css";

const AppContext = createContext({});
export default function App() {
  const [ name, setName ] = useState("张三");
  return (
    <div>
      <h1>我是父组件</h1>
      <AppContext.Provider value={{ name: name }}>
        <Child />
      </AppContext.Provider>
    </div>
  );
}

function Child() {
  return (
    <div>
      <h2>我是子组件</h2>
      <Grand />
    </div>
  );
}

function Grand() {
  const { name } = useContext(AppContext);
  return (
    <div>
      <h3>我是孙组件: App组件name为:{name}</h3>
    </div>
  );
}

           
常用React Hooks简单上手

在父组件中通过

createContext

来创建出一个上下文,并在挂载子组件的位置提供

Provider

来给后代组件中提供数据,在需要使用数据的子孙组件中,使用

useContext

来使用父组件传递过来的数据。

useReducer

顾名思义,

useReducer

可以让function组件使用redux,用法:

useReducer

接收三个参数,第一个参数为改变状态的reducer方法,第二个参数为初始化的state数据,第三个参数可以接收一个惰性初始化函数,用于计算返回一个初始化state数据。

例子:

import { useReducer, useRef } from "react";
import "./styles.css";

const initState = 0;
const reducer = (state = initState, action) => {
  switch (action.type) {
    case "add":
      return state + action.value;
    case "minus":
      return state - action.value;
    default:
      return state;
  }
};
export default function App() {
  const InputRef = useRef();
  const [state, dispatch] = useReducer(reducer, initState);
  const add = () => {
    dispatch({ type: "add", value: InputRef.current.value * 1 });
  };
  const minus = () => {
    dispatch({ type: "minus", value: InputRef.current.value * 1 });
  };
  return (
    <div className="App">
      <h1>我是父组件</h1>
      <p>Count: {state}</p>
      <input ref={InputRef} />
      <button onClick={add}>加</button>
      <button onClick={minus}>减</button>
    </div>
  );
}
           

自定义Hook

我们还可以通过自定义一些Hook来满足我们开发的需要,例如,封装一个获取列表数据的Hook,

伪代码:

import { useState, useEffect } from "react";
import "./styles.css";

const fetchInitData = () => {
  const [dataList, setDataList] = useState([])
  useEffect(async () => {
    await ajax.get('/getDataList').then(res => {
      setDataList(dataList)
    })
  },[])

  return {
    dataList,
    setDataList
  }
}
export default function App() {
  useEffect(() => {
    fetchInitData()
  },[]) 
  return (
    <div className="App">
      <h1>我是父组件</h1>
    </div>
  );
}
           

码字不易,给个赞再走吧~

继续阅读