react 常見 hook 函數(shù)

react 函數(shù)組件和 React Hooks 注意事項

1.  函數(shù)組件:函數(shù)組件又被稱為無狀態(tài)組件,因為在函數(shù)組件中無法使用 this 和生命周期、無法定義 state,函數(shù)組件數(shù)據(jù)來源是接受父組件傳遞的 props 參數(shù)或者 redux 數(shù)據(jù),所以函數(shù)組件一般只能用來渲染頁面,但是 react Hooks 可以讓函數(shù)組件做更多的事
2.  React Hooks 是 react 16.8.0 新增特性,它可以讓函數(shù)組件擁有一些類組件特性,比如定義修改 state、組合生命周期,性能優(yōu)化等
3.  hook 函數(shù)只能在函數(shù)組件內部使用,不可在函數(shù)組件外或者類組件中使用
4.  只能在函數(shù)最外層調用 hook, 不要在循環(huán),條件或嵌套函數(shù)中調用 hook

一、useState() 在函數(shù)組件中定義和修改 state

useState() 可傳入任意類型參數(shù)(初始值),返回一個數(shù)組,數(shù)組中第一個值是初始值的響應式數(shù)據(jù)第二個值是修改響應式數(shù)據(jù)的方法

  1. 在 src/App.js 中定義和修改響應式數(shù)據(jù)
import { useState } from "react";

// 父組件
function App() {
  return (
    <div>
      <A title={"云想衣裳花想容"}></A>
    </div>
  );
}

// 子組件
function A(props) {
  // 定義數(shù)字類型響應式數(shù)據(jù)
  const [count, setCount] = useState(1);

  // 定義對象類型響應式數(shù)據(jù)
  const [userinfo, setUserinfo] = useState({
    name: "alias",
    age: 20,
  });

  // 定義函數(shù)類型響應式數(shù)據(jù),通常用于接收 props 參數(shù)
  const [propsTitle, setPropsTitle] = useState(() => {
    return props.title;
  });
  return (
    <div>
      <div>
        {/* 數(shù)字 */}
        <h1>useState Number</h1>
        <p>count: {count}</p>
        <button
          onClick={() => {
            setCount(count + 1);
          }}
        >
          count ++
        </button>
        <hr />
      </div>
      <div>
        {/* 對象 */}
        <h1>useState Object</h1>
        <p>姓名:{userinfo.name}</p>
        <p>年齡:{userinfo.age}</p>
        <button
          onClick={() => {
            setUserinfo({
              ...userinfo,
              age: userinfo.age + 1,
            });
          }}
        >
          age ++
        </button>
        <hr />
      </div>
      <div>
        {/* props */}
        <h1>useState props</h1>
        <p>標題:{propsTitle}</p>
        <button
          onClick={() => {
            setPropsTitle(propsTitle + "1");
          }}
        >
          props.title ++
        </button>
        <hr />
      </div>
    </div>
  );
}

export default App;

二、useReducer() 在函數(shù)組件中定義和修改 state

使用方式類似 Redux

第一步:定義store
第二步:定義reducer
第三步:給 useReducer() 傳入reducer 和 store ,返回組件狀態(tài)state和操作狀態(tài)的方法dispatch()
第四步:在組件 return 的模板中使用 state 渲染頁面,通過dispatch()修改state
  1. 在 src/App.js 中定義和修改響應式數(shù)據(jù)
import { useReducer } from "react";

// 父組件
function App() {
  return (
    <div>
      <A title={"云想衣裳花想容"}></A>
    </div>
  );
}

// 子組件
function A(props) {
  // 1. 定義 store
  const store = {
    count: 1,
    userinfo: {
      name: "alias",
      age: 20,
    },
    propsTitle: props.title,
  };

  // 2. 定義reducer
  const reducer = (prevState, action) => {
    switch (action.type) {
      case "count":
        return { ...prevState, count: action.count };
      case "userinfo":
        return { ...prevState, userinfo: action.userinfo };
      case "propsTitle":
        return { ...prevState, propsTitle: action.propsTitle };
      default:
        return prevState;
    }
  };

  // 3. 給 useReducer() 傳入reducer 和 store ,返回組件狀態(tài)state和操作狀態(tài)的方法dispatch()
  const [state, dispatch] = useReducer(reducer, store);

  return (
    <div>
      <div>
        <h1>count</h1>
        <p>count: {state.count}</p>
        <button
          onClick={() => {
            dispatch({ type: "count", count: state.count + 1 });
          }}
        >
          count ++
        </button>
        <hr />
      </div>
      <div>
        <h1>userinfo</h1>
        <p>姓名:{state.userinfo.name}</p>
        <p>年齡:{state.userinfo.age}</p>
        <button
          onClick={() => {
            dispatch({
              type: "userinfo",
              userinfo: {
                ...state.userinfo,
                age: state.userinfo.age + 1,
              },
            });
          }}
        >
          age ++
        </button>
        <hr />
      </div>
      <div>
        <h1>propsTitle</h1>
        <p>標題:{state.propsTitle}</p>
        <button
          onClick={() => {
            dispatch({
              type: "propsTitle",
              propsTitle: state.propsTitle + "1",
            });
          }}
        >
          props.title ++
        </button>
        <hr />
      </div>
    </div>
  );
}

export default App;

三、useEffect() 在函數(shù)組件中使用生命周期

1. useEffect() 可傳入兩個參數(shù),第一個參數(shù)為回調函數(shù),第二個參數(shù)為依賴數(shù)組
2. 組件初始化時執(zhí)行所有 useEffect() 函數(shù)的第一個回調函數(shù):相當于類組件中的 componentDidMount 生命周期
3. 組件卸載時執(zhí)行所有 useEffect() 函數(shù)的第一個回調函數(shù)中 return 的函數(shù):相當于類組件中的 componentWillUnmount 生命周期
4. 組件狀態(tài)變更時根據(jù)第二個數(shù)組參數(shù)決定是否執(zhí)行 useEffect() 函數(shù)的第一個回調函數(shù):相當于類組件中的 componentDidUpdate 生命周期
當不給 useEffect() 傳入第二個數(shù)組參數(shù)時,任意狀態(tài)數(shù)據(jù)變更都會執(zhí)行 useEffect() 函數(shù)的第一個回調函數(shù)
當給 useEffect() 傳入第二個數(shù)組參數(shù)為 `[]` 時,任意狀態(tài)變更都不執(zhí)行 useEffect() 函數(shù)的第一個回調函數(shù),只是初始化執(zhí)行
當給 useEffect() 傳入第二個數(shù)組參數(shù)為 `[state1,state2 ...]` 某些狀態(tài)時,只有傳入的狀態(tài)變更才執(zhí)行 useEffect() 函數(shù)的第一個回調函數(shù)
  1. 在 src/App.js 中,點擊按鈕測試
import { useState, useEffect } from "react";

// 父組件
function App() {
  const [show, setShow] = useState(true);
  return (
    <div>
      <div>{show ? <A title="云想衣裳花想容"></A> : "hello world"}</div>
      <hr />
      <button
        onClick={() => {
          setShow(!show);
        }}
      >
        是否卸載子組件
      </button>
    </div>
  );
}

// 子組件
function A(props) {
  const [count, setCount] = useState(1);
  const [userinfo, setUserinfo] = useState({
    name: "alias",
    age: 20,
  });
  const [propsTitle, setPropsTitle] = useState(() => {
    return props.title;
  });

  // 當useEffect()不傳入第二個參數(shù)時:初始化和任何狀態(tài)變更執(zhí)行第一個回調函數(shù)參數(shù)
  useEffect(() => {
    console.log(count);
    console.log(userinfo);
    console.log(propsTitle);
    console.log("-------- no ------------");
  });

  // 當useEffect()第二個參數(shù)為[]時:只是初始化執(zhí)行第一個回調函數(shù)參數(shù),狀態(tài)變更不會執(zhí)行
  useEffect(() => {
    console.log(count);
    console.log(userinfo);
    console.log(propsTitle);
    console.log("---------- [] ----------");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 當useEffect()第二個參數(shù)為某些具體狀態(tài)時:初始化和具體狀態(tài)變更執(zhí)行第一個回調函數(shù)參數(shù),其他狀態(tài)變更不會執(zhí)行
  useEffect(() => {
    console.log(userinfo);
    console.log("---------- [userinfo] ----------");
  }, [userinfo]);

  // 當在第一個回調函數(shù)參數(shù)中return一個函數(shù)時:初始化執(zhí)行第一個回調函數(shù)和當前組件卸載執(zhí)行return的函數(shù)
  useEffect(() => {
    console.log(propsTitle);
    console.log("---------- [propsTitle] return () => {} ----------");
    return () => {
      console.log("組件卸載執(zhí)行");
    };
  }, [propsTitle]);

  return (
    <div>
      <div>
        <h1>useState Number</h1>
        <p>count: {count}</p>
        <button
          onClick={() => {
            setCount(count + 1);
          }}
        >
          count ++
        </button>
        <hr />
      </div>
      <div>
        <h1>useState Object</h1>
        <p>姓名:{userinfo.name}</p>
        <p>年齡:{userinfo.age}</p>
        <button
          onClick={() => {
            setUserinfo({
              ...userinfo,
              age: userinfo.age + 1,
            });
          }}
        >
          age ++
        </button>
        <hr />
      </div>
      <div>
        <h1>useState props</h1>
        <p>標題:{propsTitle}</p>
        <button
          onClick={() => {
            setPropsTitle(propsTitle + "1");
          }}
        >
          props.title ++
        </button>
        <hr />
      </div>
    </div>
  );
}
export default App;

四、useRef() 在函數(shù)組件中獲取 DOM 節(jié)點

  1. 在 src/App.js 中
import { useRef } from "react";

function App() {
  const elTitle = useRef(null);
  return (
    <div>
      <h1 ref={elTitle}>useRef</h1>
      <button
        onClick={() => {
          console.log(elTitle);
          console.log(elTitle.current);
          console.log(elTitle.current.innerText);
        }}
      >
        get element
      </button>
    </div>
  );
}

export default App;

五、useContext(),用于后代傳參獲取 Context 參數(shù)

  1. 在 src/App.js 中
import { useState, createContext, useContext, Component } from "react";
const countContext = createContext();

// 父組件
function App() {
  const [count, setCount] = useState(1);
  return (
    <div>
      <h1>APP</h1>
      <button onClick={() => setCount(count + 1)}>count +1</button>
      <hr />
      <countContext.Provider value={count}>
        <A />
      </countContext.Provider>
    </div>
  );
}

// 子組件A:獲取 Context 參數(shù)方式一
class A extends Component {
  render() {
    return (
      <countContext.Consumer>
        {(count) => (
          <>
            <h1>A</h1>
            <p>count: {count}</p>
            <hr />
            <B />
          </>
        )}
      </countContext.Consumer>
    );
  }
}

// 后代組件B:獲取 Context 參數(shù)方式二,通過 useContext 函數(shù)獲取參數(shù)
function B() {
  const count = useContext(countContext);
  return (
    <>
      <h1>B</h1>
      <p>count: {count}</p>
      <hr />
    </>
  );
}

export default App;

六、memo() 組件記憶優(yōu)化

在 react 組件中,當父組件的任意狀態(tài)發(fā)生變更時,依賴父組件的所有子組件都會重新渲染,我們希望只有當父組件傳遞給子組件的 props 發(fā)生變更時,子組件才會重新渲染

1. 在類組件中,通過 PureComponent 或者 shouldComponentUpdate 進行優(yōu)化
2. 在函數(shù)組件中使用 memo() 高階組件進行優(yōu)化: memo() 傳入兩個參數(shù),第一個參數(shù)是子組件,第二個參數(shù)是回調函數(shù),只有當?shù)诙€回調函數(shù)返回true時才會重新渲染子組件
3. 一般不傳第二個參數(shù)(不傳:只有當子組件依賴父組件的props發(fā)生變化才重新渲染子組件,傳:狀態(tài)變化滿足某個條件才重新渲染子組件)
  1. 在 App.js 中
import { useState, memo } from "react";

// 父組件
function App() {
  const [count, setCount] = useState(1);
  const [msg, setMsg] = useState("云想衣裳花想容");

  return (
    <>
      <h1>App</h1>
      <div>count: {count}</div>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        only count +1
      </button>
      <div>msg: {msg}</div>
      <button
        onClick={() => {
          setMsg(msg + "1");
        }}
      >
        only msg +1
      </button>
      <hr />
      <A msg={msg}></A>
    </>
  );
}

// 子組件
const A = memo(function (props) {
  console.log("A 組件重新渲染");
  return (
    <>
      <h1>A</h1>
      <div>props.msg: {props.msg}</div>
    </>
  );
});
export default App;

七、useMemo() 狀態(tài)值記憶優(yōu)化

在 react 組件中,任意狀態(tài)變更都會重新執(zhí)行所有用于頁面渲染的計算函數(shù),但是我們希望只有當計算函數(shù)依賴的狀態(tài)發(fā)生變化時才執(zhí)行計算函數(shù)

1. useMemo 優(yōu)化:useMemo()返回記憶的值,傳入兩個參數(shù),第一個參數(shù)是回調函數(shù),第二個參數(shù)是依賴數(shù)組,只有當?shù)诙€依賴數(shù)組中的狀態(tài)發(fā)生變化時才會執(zhí)行第一個回調函數(shù)
2. 通常第二個依賴數(shù)組存放第一個回調函數(shù)中用到的所有狀態(tài) [state1,state2 ...]
3. 類似 VUE 中的 computed 計算屬性,只有當組件初始化和依賴狀態(tài)改變時才會重新計算
  1. 在 App.js 中
import { useState, useMemo } from "react";

// 父組件
function App() {
  const [count, setCount] = useState(1);
  const [msg, setMsg] = useState("云想衣裳花想容");

  // 任何狀態(tài)變更都會重新執(zhí)行 funCount()
  const funCount = () => {
    console.log("funCount count變更");
    return count * 2;
  };

  // 優(yōu)化:只有當 msg 狀態(tài)變化才會執(zhí)行回調,否則不執(zhí)行
  const memoMsg = useMemo(() => {
    console.log("memoMsg msg變更---------------------------");
    return msg + "1";
  }, [msg]);

  return (
    <>
      <h1>App</h1>
      <div>funCount: {funCount()}</div>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        count +1
      </button>
      <div>memoMsg: {memoMsg}</div>
      <button
        onClick={() => {
          setMsg(msg + "1");
        }}
      >
        only msg +1
      </button>
      <hr />
    </>
  );
}
export default App;

八、useCallback() 函數(shù)記憶優(yōu)化

在 react 組件中,當父組件給子組件傳遞的參數(shù)含有函數(shù)時,父組件的任意狀態(tài)變更都會促使子組件重新渲染,就算用 memo() 包裹子組件也不行,但是我們希望子組件不重新渲染

1. useCallback 優(yōu)化:useCallback()返回記憶的函數(shù),傳入兩個參數(shù),第一個參數(shù)是回調函數(shù),第二個參數(shù)是依賴數(shù)組,
只有當?shù)诙€依賴數(shù)組中的狀態(tài)發(fā)生變化時才會返回新函數(shù),注意:不是記憶函數(shù)而是新函數(shù),會促使子組件更新,與 useMemo() 相反
2. 通常第二個依賴數(shù)組是 []
  1. 在 App.js 中
import { useState, memo, useCallback } from "react";

// 父組件
function App() {
  const [count, setCount] = useState(1);
  const [msg, setMsg] = useState("云想衣裳花想容");

  const log = useCallback(() => {
    // 如果不用 useCallback 包裹,那么每次父組件任意狀態(tài)變更都會刷新子組件,就是使用 memo() 包裹子組件也不行
  }, []);
  return (
    <>
      <h1>App</h1>
      <div>count: {count}</div>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        only count +1
      </button>
      <div>msg: {msg}</div>
      <button
        onClick={() => {
          setMsg(msg + "1");
        }}
      >
        only msg +1
      </button>
      <hr />
      <A msg={msg} log={log}></A>
    </>
  );
}

// 子組件
const A = memo(function (props) {
  console.log("A 組件重新渲染");
  return (
    <>
      <h1>A</h1>
      <div>props.msg: {props.msg}</div>
    </>
  );
});
export default App;
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容