Original address: github.com/whinc/blog/…

Introduce constate

Constate is a lightweight state management library based on React Hooks and React Context.

The main function of ConState is to promote the execution results of custom Hooks into Context, use React Context communication mechanism, and provide the results to sub-components for consumption, thus achieving cross-component state sharing.

Constate Example

Here is an example provided by Constate:

import React, { useState } from "react";
import createContextHook from "constate";
 
// Create custom Hooks
function useCounter() {
  const [count, setCount] = useState(0);
  const increment = (a)= > setCount(prevCount= > prevCount + 1);
  return { count, increment };
}
 
// Call the createContextHook() function provided by Constate with custom Hooks as arguments,
// And returns a new function useCounterContext
const useCounterContext = createContextHook(useCounter);
 
/ / use the < useCounterContext. The Provider > as the root component, providing Shared container status
function App() {
  return( <useCounterContext.Provider> <Count /> <Button /> </useCounterContext.Provider> ); } // subcomponent <Button> function Button() {// Call useCounterContext() to get custom Hooks useCounter const {increment} = useCounterContext(); // Call INCREMENT to update state count in custom hooks Cause component < useCounterContext. The Provider > update return < button onClick = {increment} > + < / button >; } // subcomponent <Count> function Count() {// Call useCounterContext() to get return result from custom Hooks useCounter const {Count} = useCounterContext(); / / when < useCounterContext. The Provider > update to render the return < span > {count} < / span >; }Copy the code

In this code, we call the createContextHooks function provided by ConState, passing in custom Hooks useCounter as an argument, which returns a new Hooks useCounterContext, Use it in the child component to get the internal state of useCounter, count and increment, so you can use the state in custom Hooks in the child component.

Constate is implemented based on React Context, so you need to wrap child components with components like context.provider. Example is the corresponding userCounterContext. The Provider (internal actual is packing the Context. The Provider, will further introduce below).

You can also modify the example online and see the results.

Constate principle analysis

Here is the simplified constate implementation code, written in TypeScript, with some extraneous code removed to highlight the point. (Constate is still under update, source code may be different)

function createContextHook<P, V>(useValue: (props: P) => V) { const Context = React.createContext({}); const Provider: FunctionComponent<P> = props => {// Execute the Hooks passed in to get the result and use the result as the value of the Context container, This way the component can get const value = useValue(props) via < context.consumer > or useContext(); return ( <Context.Provider value={value}> {props.children} </Context.Provider> ); }; Const useContext = () => react.usecontext (Context); const useContext = () => react.usecontext (Context); const useContext = () => react.usecontext (Context); useContext.Context = Context; useContext.Provider = Provider; return useContext; }Copy the code

The implementation of constate is relatively simple from the source code: Constate internally defines a Provider component and uses the return value of the custom Hooks passed in as the value of the Context. Constate eventually returns an Hooks, UseContext is actually executed after the Hooks call to get the value in the Context, which is the return value of the custom Hooks passed in.

Below is a call diagram I drew, with blue squares for external user code and gray squares for internal implementation code.

Through several Q&A, focus on the understanding of several important points.

  1. How does the child component get the return value of the custom Hooks?

A: Pass the value returned by custom Hooks to the < Context.provider > component and use that component as the ancestor of the child component that gets the value from the React Context using the cross-component communication mechanism.

  1. How does a child component update a value in the Context container?

A: When a child component updates, it calls custom Hooks that return the update function (as in increment in the example), which eventually calls the update function returned by useState(as in setCount in the example), This will cause the custom Hooks place components (such as example, the useCounterContext. The Provider) to render, and update the value.

  1. How does child component A affect the display of child component B?

The root component updates the React Context. The root component also updates the React Context, and the child component B displays the latest values.

summary

Hooks can be used after they are imported, regardless of component hierarchy. Constate takes advantage of this by encapsulating React Context and useContext, allowing us to use the result of custom Hooks in any child component after defining the Provider for the root component.

The benefits are first state sharing based on Context, and second, scalability. Scaling means that at first state can be stored in custom Hooks, like state inside a component. When it is found that the internal state of a component needs to be shared by other components, constate is used to lift the state returned by custom Hooks into the Context for state sharing. Smooth transition from component internal state to shared state without modifying code for custom Hooks.

Constate essentially encapsulates the Context, establishing communication between parent and child components to simplify context-based state sharing. This was done before hooks, but using class components + higher-order components.