Using hooks and connect to access the same store

Keywords: Javascript React JSON

It has been several months since React Hooks was officially released. redux and mobx also support the use of Hooks. Is it possible to use react context API & Hooks to realize a store that supports class component and functional component access at the same time? The answer is yes.

Since we are based on Context Api, let's create a context object first

// store.js
import React from 'react'

const initialStore = {}
const StoreContext = React.createContext(initialStore)
 

Next, we construct two ways to access the store:

How to look:

// store.js
import {useReducer, useContext} from 'react'

// Declare reducer
export const reducer = (state, action) => {
  switch (action.type) {
    case 'set':
      return { ...state, ...action.payload }
    case 'reset':
      return {}
    default:
      throw new Error(
        `action: '${action.type}' not defined`
      )
  }
}

// Implementation based on native Hooks
export const useStore = () => {
  return useReducer(reducer, useContext(StoreContext))
}

HOC mode:
HOC needs a context environment to access the store, so let's construct the provider first

// Construct a root component Provider
export const StoreProvider = ({ children }) => {
  const [context, dispatch] = useStore()
  return <StoreContext.Provider value={{ ...context, dispatch }}>{children}</StoreContext.Provider>
}

The StoreProvider can be wrapped in the outermost layer of the root component like the react Redux Provider.

And then come to consumer

export const connect = (WrappedComponent) => {
  return class ConnectClass extends React.Component {
    render () {
      return (
        <StoreContext.Consumer>
          {
            state => <WrappedComponent {...state} {...this.props} />
          }
        </StoreContext.Consumer>
      )
    }
  }
}

We encapsulate a connect function, which is similar to the single parameter form of connect in react redux.

So how should we use it in components?

Class Component

import React from 'react'
import { connect } from 'store'

export default @connect class Component extends React.Component {
  handleClick = () => {
    this.props.dispatch({type: 'set', payload: {a: 1}})
  }

  render() {
    return (<div>
      <div onClick={this.handleClick}>{JSON.stringify(this.props)}</div>
      <div>{JSON.stringify(this.props)}</div>
    </div>)
  }
}

Functional Component


import React from 'react'
import { useStore } from 'store'

export default const Component = () => {
  const [store, dispatch] = useStore()
  const handleClick = () => {
    dispatch({type: 'set', payload: {a: 1}})
  }

  return (<div>
      <div>{JSON.stringify(store)}</div>
      <div onClick={handleClick}>{JSON.stringify(store)}</div>
    </div>)
}

At this point, we have realized cross component communication based on react native api. The access of hooks and HOCs is realized through context api, and shallow comparison is supported by default.

Posted by welsh_sponger on Mon, 04 Nov 2019 11:41:22 -0800