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.