This is the fourth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

A globally unique store is provided in Concent, which is composed of several modules, and each module is composed of State, Reducer, computed, watch, and Lifecycle respectively

The module

Each part can be written as JS files in a module folder to form a complete model definition (dispatch calls of internal functions can be directly based on references instead of strings after the reducer independent definition). Add an index.js to the model file to merge and expose the configuration interface.

Default module: $$default is the configuration that needs to be displayed, otherwise it is an empty module. If the default module instance state and module state are independent of each other, the setState of the instance will not trigger the change of module data.

Global module: $$global, also requires display configuration

The state module

Definition: Put attributes that need to be shared in state to achieve global sharing

const state= {
  token: '',
  selectedOrgId: null,
  selectedProjId: null,
}
Copy the code

Access to:

  • Ctx. state Retrieves state

  • Ctx. moduleState Gets the state that belongs to the module

    const { moduleState } = useConcent<AnyObject, Ctx>({module: 'user'})
    
    {moduleState.user.selectedOrgId}
    Copy the code
  • Ctx. globalState gets the built-in globalState

  • Ctx. connectedState {meduleState} Gets the state on the connection

Reducer module

Definition: The Reducer object is a collection of functions generated by the fragment state. Key is the function name and value is the fragment state generating function, which is responsible for generating and returning new partial states.

Trigger:

  • Instance ctx.dispatch is triggered

    • Actionctx. dispatch is internally triggered to trigger the other Reducer functions

      const result = await actionCtx.dispatch(login, params)
      Copy the code
  • Instance ctx. Settings to call pre-triggered function ()

    Setup is triggered once before the component is first rendered, and the result is collected in ctx. Settings. You can define instance hook functions in the setup function body to save the component time from repeated rendering.

HandleJoinSubmit: async (data: UserParams): Promise<void> => {setState({message: '' }) const state = await moduleReducer.join(data) const isLogin = Boolean(state.token) if (isLogin) { history.push('/account/setup') }Copy the code
// import Settings const {Settings} = useConcent<InstProps, InstCtx>({setup, module: 'user', props: {the history, the from}}) / / bind on DOM < JoinForm onSubmit = {Settings. HandleJoinSubmit} / >Copy the code
  • ctx.reducer.{moduleName} {functionName}
    const { moduleState, moduleReducer } = useConcent({ module: 'user' })

     const handleOrgChange = React.useCallback(
       (value) => {
          moduleReducer.orgChange(value)
       },
       [moduleReducer]
     )
Copy the code

The computed module

Comouted can define multiple calculation result key retkeys, each reKey corresponds to a calculation function, when the module is first loaded in order to execute all the calculation function in the defined order and cache their results.

export const isLogin = {
  fn: ({ token, isTokenVerifyEnd }: UserSt): boolean => isTokenVerifyEnd && Boolean(token),
  depKeys: ['token', 'isTokenVerifyEnd'],
}
Copy the code

Collect dependencies: The calculation function is triggered when the values in the depKeys dependency list change.

Lifecycle module

Provides five optional life cycle functions: initState, initStateDone, loaded, mountd, and willUnmount

  • InitState State of asynchronous initialization

  • InitStateDone initState Specifies the service logic after execution

  • The work performed when the module is loaded. Loaded can be used instead of initState

    Export function loaded(dispatch: D): void {dispatch(rd.initstate)}Copy the code
  • Mounted The driver is triggered only once after the component instance is mounted. If the driver is triggered repeatedly, false is returned

  • WillUnmount A function that needs to be triggered when the last component is unmounted, usually for cleanup

Global API

  • Know to userunCentralized configuration modules,configureDecentralized configuration modules
  • Know to useregister,registerDumb,useConcentCertified components
  • Know to usesetState,dispatchModify the state of

The run function

  • The run function is responsible for loading the user-defined module configuration and starting Concent. Other top-level function calls must follow the run call
  • Call can callimport {run} from 'concent'Put it in the entry function index.
  • The first argument to the run function is the store configuration item that starts Concent, which maintains the globally unique ConcentContext object
import { run } from 'concent'
import * as models from '@/models'

run(models, { log: __DEV__ })
Copy the code

Register function (less used)

Register module information of the class component, and the Concent instantiation component will read the registration information to generate the corresponding instance context.

UseConcent function

Registering module information for function components, Concent instantiates the component and reads the instance context of the response generated from the registration information

  • Use method: 1. Export directly from concent module, 2. Call from default export

    import {useConcent} from 'concent'
    useConcent()
    
    import cc from 'concent'
    cc.useConcent()
    Copy the code
  • The instance context CTX is returned when the owning module is registered

    const ctx = useConcent('foo')
    
    const ctx = usConcent({module:'foo'})
    Copy the code
  • You can read the data state in a module or modify the data in a module with setState

    const {state} = useConcent({module:'foo'})
    
    const {setState} = useConcent({module:'foo'})
    const changeName = e =>setState({name: e.target.value})
    Copy the code
  • If the reducer provides corresponding methods, Mr And Dispatch can be used to punish the modification

    const {mr,dispatch} = useConcent({module:'foo'}) const changeName = e =>mr.changeName(e.target.value) const changeName =  e => dispatch('changeName',e.target.value)Copy the code
  • When a component needs to consume data from multiple modules, the connect parameter can be used to declare multiple modules to be connected. Ctx.connectedstate gets data from the target module

    const {connectedState:{bar,baz}} = useConcent({connect:['bar','baz']})
    Copy the code
  • If the Reducer provides corresponding methods, you can use CR and dispatch to trigger the Reducer method of the module to modify data

    const {cr,dispatch} = useConcent({connect:['bar','baz']})
    const changeName = e => cr.bar.changeName(e.target.value)
    const changeName = e => dispatch('bar/changeName',e.target.value)
    Copy the code
  • Configure both Module and Connect to implement scenarios that belong to one module and connect to multiple modules

    const {state,connectedState} = useConcent({module:'foo',connect:['bar','baz']})
    Copy the code

The instance

Instance context

After being instantiated by the Concent component, a RefContext instance context object is created. All instance interfaces are provided by the RefContext.

Each component instance has a reference, CTX, to the instance context object that Concent builds for it, which is built during instance initialization and stored in the global context until instance destruction is removed from the global context.

The module information carried on the CTX allows Concent to know exactly how to distribute the submitted state to other instances. All instance apis, associated states, calculation results, and so on are mounted on the CTX object.

Get context: You can get CTX directly from the function component

const ctx = useConcent('counter')
Copy the code

The instance setup

Setup is triggered once before the component is first rendered, and the result is collected in ctx. Settings. You can define instance hook functions in the setup function body to save the component time from repeated rendering.

Examples of effect

The setup function can be executed only once before both the class component and the instance component are first rendered. Side functions defined by the Setup function can achieve the effect of unifying the function component lifecycle.

const setup = (ctx) =>{
const {effect} = ctx
  effect(() => {
    if (moduleComputed.isLogin) {
      history.push(from)
   }
 }, ['token'])
}
Copy the code
  • There’s only one function, which gets executed every turn, equivalent to didMount+didUpdata
  • Set the third bit of the argument to NULL, indicating that there are no dependencies and that each round is executed. Setting the fourth parameter to false means that it is not executed on the first rendering. Equivalent didUpdate
  • Set the third bit of the dependency array to [], indicating that only the first render is performed
  • The third argument [‘count’] is executed only when the count value changes, after the first rendering. (Note that the stateKey name is passed here, and Concent will automatically compare the count value at the last moment to whether the count value is different at the current moment to determine whether to fire the side effect function.)
  • EffectProps is the same as effect, except that the array is passed the propsKey name