17
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

React hooksこんな風に使ってみたよ

Last updated at Posted at 2019-07-10

バイトでReactを使うことになり、hooksの利用を強行提案して書いて見たところ、楽しすぎたのでどんな感じで使っているかを紹介したい。

あくまでこんな感じで使ってみたよって話なので、良いプラクティスかどうかは自己判断でお願いします

そもそもなんでhooksを利用するのか

公式ドキュメントから引用すれば

ステートフルなロジックをコンポーネント間で再利用する

ためです。今まではHoCとかで管理してたものをhooksでやりやすくした感じですね。

例1) 初期化するときの非同期通信の共通化

まずは単純にuseEffect(あるいはcomponentDidMount)内のfetchしてjsonにしてみたいなロジックを一箇所にまとめてみる

useInitFetch.js
import { useEffect } from 'react';

export function useInitFetch(path, callback) {
  useEffect(() => {
    fetch(`http://path/to/api/${path}`)
      .then(res => res.json())
      .then(res => ({data: res}),
            e => ({error: e}))
      .then(res => callback(res));
  }, []);
}

使い方は

MyComponent.jsx
import React, { useState } from 'react';
import { useInitFetch } from './useInitFetch'

export const MyComponent = () => {
  const [value, setValue] = useState({});
  useInitFetch('path/to/value', (res) => setValue(res));
  return <div>{value}</div>
}

例2) socket.ioの通信をどのコンポーネントからも呼び出せるようにする

useSocketはこんなことができるようにしました

  • いろんなところからsocket.emitを呼び出したいが、socket自体はコンポーネントの表現には関わらないので、バケツリレーを避けたい -> context apiを利用
  • 間違ってio.connectをなんども呼び出さないようにしたい -> 同じくcontext apiで解決可能
  • あるコンポーネントがマウントするまでイベントを登録したくない・アンマウント後はイベントを削除したい -> useEffectのクリーンアップを利用
useSocket.jsx

import React, { useContext, useEffect, useState, createContext } from 'react';
import io from 'socket.io-client';

export const socketContext = createContext();

export const SocketProvider = ({children}) => {

  const [socket, _] = useState(() => io.connect('http://path/to/socketapi'));

  useEffect(() => {
    return function cleanup() {
      socket.close();
    }
  }, []);

  return (
    <socketContext.Provider value={socket}>
      {children}
    </socketContext.Provider>
  )
}

export const useSocket = (setEvent, removeEvent) => {
  
  const socket = useContext(socketContext);

  useEffect(() => {
    setEvent(socket);
    return () => {
      removeEvent(socket);
    }
  }, []);

  return socket;
}

使い方:

MyComponent.jsx
import React, { useState } from 'react';
import { SocketProvider, useSocket } from './useSocket';

export const MyComponent = () => {
  const [value, setValue] = useState({});
  const socket = useSocket((socket) => {
    socket.on('myevent', (res) => {
      setValue(res);
    });
  }, (socket) => {
    socket.off('myevent');
  });

  return (
    <>
      {value}
      <button onClick={() => socket.emit('myevent2', 'hoge')>Click!</button>
    </>
  )

  export const App = () => {
    return (
      <SocketProvider>
         <MyComponent />
      </SocketProvider>
}

これに限ったことではないですが、hooks + context APIは特にグローバルに唯一存在してほしい変数がある時にとても強力であると感じました

例3) 別Windowで開く&別Windowは最大1つまで

同じくcontext api + hooksを利用できます。

useNewWindow.jsx
import { useState, createContext } from 'react';


export const windowContext = createContext();

export const WindowProvider = ({children}) => {
  const [win, setWin] = useState(null);

  return (
    <windowContext.Provider value={[win, setWin]}>
      {children}
    </windowContext.Provider>
  )
}

export const useNewWindow = (title, features) => {
  const [win, setWin] = useContext(windowContext);

  return (url) => {
    if(win === null || win.isClosed) {
      setWin(window.open(url, title, features));
    }
  }
}

使い方:

MyComponent.jsx
import React, { useState } from 'react';
import { WindowProvider, useNewWindow } from './useNewWindow';

export const MyComponent = () => {
  const openWindow = useNewWindow('HogeTitle', 'resizable=yes,scrollbars=yes');

  return (
    <button onClick={() => openWindow('path/to/newWindow')}>Open Window</button>
  )

  export const App = () => {
    return (
      <WindowProvider>
         <MyComponent />
      </WindowProvider>
    )
  };
}

まとめ

なんかhooksがいいっていうよりcontext apiがいいみたいな記事になってしもうた

useRefとかuseMemoとかまだまだ面白そうな機能がいっぱいなので、使う場面があったら更新していきます

17
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?