😄

React Hooksの10種類を理解する(Basic: useContext)

2021/07/12に公開

React Hooksの10種類を理解する(Basic: useContext)

contextの復習

contextとは

  • contextは、各階層で手動でプロパティを子にわたすことなく、component tree内でデータを渡す方法を提供するものある。
  1. React.createContext
const newContext = React.createContext(defaultValue);
  • context objectを作成する。Reactがこのcontext objectが登録されているcomponentをrenderする際には、tree内の最も近い上位の一致する Provider から現在のcontextを読み取る。

  • defaultValue 引数は、componentがtree内の上位に対応するProviderを持っていないときのみに使用される。

  1. Context.Provider
<NewContext.Provider value={...}>
  • このprovider componentは、valueプロパティを受け取り、子要素にあるconsumer componentと接続することができる。
  • providerはnestして(まとめて)tree内のより深い位置で値を上書きすることができる。
  • providerの子孫のすべてのconsumerは、providerのvalueプロパティが変更されるたびに再renderされる。
  1. Class.contextType
  • hooksにはあまり関係ないため省略
  1. Context.Consumer
<MyContext.Consumer>
  {value => ...}
</MyContext.Consumer>
  • contextの変更を購読するreact componentである。
  • function as a childが必要となってくる。
  • 引数valueは、tree内の上位で一番近いcontext用のproviderのvalueプロパティと等しくなる。
  • 上位に存在しない場合、引数のvaluecreateContext()から渡されたdefaultValueと等しくなる。

contextに関する注意事項

  • contextは参照の同一性を使用していつ再renderするかを決定するため、providerの親が再renderするときにconsumerで意図しないrenderを引き起こす可能性がある。そのため、親のstateにvalueをリフトアップすることがある。

before

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something' /* ここが問題 */}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

after

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'}, // このstateに予めvalueを設置
    };
  }

  render() {
    return (
      <MyContext.Provider value={this.state.value}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

useContextの基本

const value = useContext(MyContext);
  • React.createContextからの戻り値を受け取り、そのcontextの現在地を返す。
  • MyContext.Providerのvalueの値によってcontextの現在地が決定される。
  • MyContext.Providerが更新された場合、このhookはMyContextproviderに渡された最新のvalueを使って再renderを発生させる。
  • useContextにわたす引数はcontext objectそれ自体
  • <MyContext.Consumer>と役割は同等。
  • useContext(MyContext)は現在のcontextの値を読み取り、その変化を購読することしかできない。よって、<MyContext.Providerが必要となってくる。

例示(公式より抜粋)

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

reference

GitHubで編集を提案

Discussion