Help us understand the problem. What is going on with this article?

ReactContext用のLoggerを作った

軽量なサービスの場合Reduxを使うのをやめてReactContextで管理するようになったんだけど、値の変更とかのタイミングでログ出してくれるredux-logger的なのあったらいいなと思ったので自作した話
(作ったの3ヶ月ぐらい前だから今だとすでにもっといいのがあるかも・・・

作ったもの

hooks/useLogger.js
import { useCallback, useEffect, useRef } from "react"
import moment from "moment"

const colors = {
  prefix: "#4CAF50",
  log: "inherit",
  prev: "#9E9E9E",
  next: "#03A9F4",
  error: "#F20404",
}

function usePrevious(value) {
  const ref = useRef(null)
  useEffect(() => {
    ref.current = value
  })
  return ref.current
}

export function useContextLogger(prefix, inputs) {
  Object.keys(inputs).forEach(key => {
    const value = inputs[key]
    const prev = usePrevious(value)
    useEffect(() => {
      const timestamp = moment().format("HH:mm:ss.SSS")
      console.group(
        `%c[${prefix}] %c${key} %c@${timestamp}`,
        `color: ${colors.prefix}`,
        `color: ${colors.log}; font-weight: bold;`,
        "color: gray; font-weight: lighter;",
      )
      console.log(`%c prev`, `color: ${colors.prev}`, prev)
      console.log(`%c next`, `color: ${colors.next}`, value)
      console.groupEnd()
    }, [value])
  })
}

使い方

10分ぐらいでぱぱっと作った例なので微妙なところ満載ですがご容赦を

contexts/todo.jsx
const TodosContext = createContext(null)
const TodosContextProvider = ({ children}) => {
  const [todos, setTodos] = useState([])

  const add = useCallback((todo) => {
    const id = todos.length + 1
    setTodos([
      ...todos,
      {
        id,
        text: todo,
        completed: false,
        createdAt: moment().format('YYYY/MM/DD HH:mm:ss'),
      }
    ])
  }, [todos])

  const toggle = useCallback((id) => {
    const todo = todos.find(t => t.id === id)
    if (!todo) return

    setTodos([
      ...todos.filter(t => t.id !== id),
      { ...todo, completed: !todo.completed },
    ].sort((a, b) => a.id - b.id))
  }, [todos])

  const remove = useCallback((id) => {
    setTodos(todos.filter(t => t.id !== id))
  })

  // ロガーで変更を監視したいパラメータをセット
  useContextLogger("TodosContext", { todos })

  return (
    <TodosContext.Provider value={{ todos, add, toggle, remove }}>
      {children}
    </TodosContext.Provider>
  )
}

こんな感じでログを仕込むと、↓のように変更前後の値がログとして吐き出される。

logger.gif

本家redux-loggerには全然及ばないけど、まぁそれなりに実用的なものが出来て満足

おまけ

単純なロガーもReactHooks使って作成したので置いとく。

hooks/useLogger.js
function useLogger(prefix) {
  const log = useCallback(
    (log, src) => {
      const timestamp = moment().format("HH:mm:ss.SSS")
      console.log(
        `%c[${prefix}] %c${log} @ %c${timestamp}`,
        `color: ${colors.prefix}`,
        `color: ${colors.log}; font-weight: bold;`,
        "color: gray; font-weight: lighter;",
        src || "",
      )
    },
    [prefix],
  )
  return { log }
}

こっちはconsole.logの代わりに使えて、useLogger呼び出す際にprefixを設定できるから、どの部分で吐かれたログかを管理するのにいい感じ。

const hogeLogger = useLogger('HogeComponent')

hogeLogger.log('test')
hogeLogger.log('obj ->', obj)

みたいに使える。

k_tada
Javascriptをこよなく愛するしがないフロントエンドエンジニアです。( ゚∀゚)o彡°React!React!
https://k-tada.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away