返回

global state with hooks

Published at 11 July, 2019

backgrounds

Problems when manage global state with hooks and context api:

Preventing rerenders with React.memo and useContext hook.

original idea

State Management with React Hooks — No Redux or Context API

clear implantation with TS

useGlobalState.ts

import { useState, useEffect, Dispatch, SetStateAction } from 'react'

type id<T> = (a: T) => T

export default function useGlobalState<T>(initialState: T) {
  let state = initialState
  let listeners: Array<Dispatch<SetStateAction<T>>> = []

  const setState = (newState: T | id<T>) => {
    if (typeof newState === 'function') {
      state = (newState as id<T>)(state)
    } else {
      state = newState as T
    }
    listeners.forEach(listener => {
      listener(state)
    })
  }

  const useCustom: () => [T, (state: T | id<T>) => void] = () => {
    const newListener = useState(initialState)[1]
    useEffect(() => {
      listeners.push(newListener)
      return () => {
        listeners = listeners.filter(listener => listener !== newListener)
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])
    return [state, setState]
  }
  return useCustom
}

usage

store.ts

import useGlobalState from './useGlobalState'

export const useGlobalCount = useGlobalState(0)

A.tsx

import React from 'react'
import { useGlobalCount } from '../store'
const A: React.FC = () => {
  const [count, setCount] = useGlobalCount()
  return (
    <div>
      <span>A {count}</span>
      <button onClick={() => setCount(count + 1)}> + </button>
    </div>
  )
}

export default A

B.tsx

import React from 'react'
import { useGlobalCount } from '../store'
const B: React.FC = () => {
  const [count, setCount] = useGlobalCount()
  return (
    <div>
      <span>B {count}</span>
      <button onClick={() => setCount(count - 1)}> - </button>
    </div>
  )
}

export default B

And you can also pass a object to useGlobalState and wrap it with mutations and actions in store.ts.


在WebGL中使用射线选择模型