天天看點

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

碼字不易,給個贊再走吧~

繼續閱讀