React Hooks

使用 useState hook

useState 可以用来管理一个组件比较简单的一两个状态,如果状态多了不适合使用 useState 管理,可以使用 useReducer.

import React, {useState} from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Counter;

使用 useEffect hook

useEffect hook 用来实现一些副作用,一般可以用作页面首次加载时读取数据。

import React, {useState, useEffect} from 'react';

function App() {
  const [isOn, setIsOn] = useState(false);

  useEffect(() => {
    let interval;
    if (isOn) {
      interval = setInterval(() => console.log('tick'), 1000);
    }
    return () => clearInterval(interval);
  }, [isOn]);
  ...
}

export default App;

在 useEffect 中返回的函数会被用来做垃圾清理。另外需要注意的是,初始化的时候总会触发一次 useEffect.

默认情况下,每次 state 有改变的时候,都会调用 useEffect 函数。如果需要更改触发的时机,那么需要使用 useEffect 的第二个参数来指定监听的事件或者说状态。当第二个参数只使用一个空数组 [] 的时候就只会在组件加载的时候调用。数组中有哪些变量,表示在这些变量变化的时候调用。

使用 useContext hook

Context 用来向所有包含的元素广播状态,或者说事件,而不需要通过组件树层层传递。

  1. 首先需要通过 React.createContext 定义一个高层次 Context,
  2. 然后在最外层使用 <MyContext.Provider /> 来包裹需要接受这个 context 的所有组件。
  3. 在需要使用状态的元素中调用 const ctx = useContext(MyContext), 然后使用 ctx 访问 Context 中的值

在基于类的 React 组件中,需要使用 <MyContext.Consumer /> 来实现读取值,现在我们都用 useContext 钩子了。

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

使用 useReducer hook

useReducer 和 useState 的用途基本是一样的,但是当需要的状态比较复杂的时候,最好使用 useReducer. 有了 useReducer 钩子,基本上可以不使用 redux 了。

const [state, dispatch] = useReducer(reducer, initialArg, init);

useReducer 通常放在管理一组状态的根元素这个层级,比如说一个页面。dispatch 函数触发事件,reducer 函数用来处理事件,更新 state.

需要注意的是,在 useReducer 的 reducer 函数中,和 redux 不同的是,不需要 state=initialState 这个参数。默认参数在调用 useReducer 的时候已经给出了。

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

useReducer + useContext = (Better) Redux

可以组合使用 useReducer 和 useContext 来实现 Redux 的功能。对于某个组件自身的数据,我们只使用 useReducer 就可以很好地管理了。然而对于多个组件都需要使用的全局数据,需要是用 useContext 来广播给所有需要该数据的组件。

两者的组合使用很简单,使用 Context.Provider 把 state 和 dispatch 这两个变量广播给 root 下的所有元素,这样在需要使用 state 和 dispatch 的地方直接 useContext(Context) 就好了。

useMemo/useCallback 钩子

用来避免重复计算或者重复生成函数。

useRef 钩子

https://stackoverflow.com/questions/56455887/react-usestate-or-useref

自定义钩子

通过灵活组合 useState, 和 useEffect, 我们完全可以创建自己的钩子。

import React from 'react';

function useOffline() {
  const [isOffline, setIsOffline] = React.useState(false);

  function onOffline() {
    setIsOffline(true);
  }

  function onOnline() {
    setIsOffline(false);
  }

  React.useEffect(() => {
    window.addEventListener('offline', onOffline);
    window.addEventListener('online', onOnline);

    return () => {
      window.removeEventListener('offline', onOffline);
      window.removeEventListener('online', onOnline);
    };
  }, []);

  return isOffline;
}

function App() {
  const isOffline = useOffline();

  if (isOffline) {
    return <div>Sorry, you are offline ...</div>;
  }

  return <div>You are online!</div>;
}

export default App;

参考

  1. https://www.robinwieruch.de/react-hooks
  2. https://www.robinwieruch.de/react-hooks-fetch-data
  3. https://medium.com/@nazrhan.mohcine/react-hooks-work-with-usestate-and-usereducer-effectively-471646cdf925
  4. https://swizec.com/blog/usereducer-usecontext-for-easy-global-state-without-libraries

及时获取更新,请关注公众号“爬虫技术学习(spider-learn)”

公众号“爬虫技术学习(spider-learn)”

About 逸飞

后端工程师

发表评论

邮箱地址不会被公开。 必填项已用*标注