usePolymerAction

background

With the popularity of React Hooks, component logic writing has become functional; logical function declarations and function code structures , as the logic increases in complexity, the code organization is chaotic, and the function declarations are scattered;
the most critical point is that everyone understands the code differently. , some like to write large sections of logic in one function, and some like to split the logic very finely, which will make the code style and code structure less and less unified
during project maintenance , making it difficult to maintain . In response to the above situation, a method that can organize code knots and sort out logic is needed to achieve high project maintainability, unified code structure, and clear logic.

design concept

abstract code structure

In the process of writing code, I found that common code structures can be abstracted;

  1. Declare variable data /shared variable declaration, state declaration/let xxx= xxx/useState
  2. Method declaration /function xx () {} /action/dispatch
  3. Method call /xx()/action()/dispatch()
  1. Through the above figure, the internal logic of common components can be divided into 3 parts, of which 3 and 4 belong to the same part:
  2. Mainly declaring data, including useState/let xxx = 11;
  3. Declaring functions and methods will involve modifying **setcounts**and using data **sendLogcount**;
    1. There will be some auxiliary methods in modification and use fetchto execute the corresponding logic;
  4. Calling methods , parts 3 and 4 all use functions and methods in the view, which are collectively called calling methods.

After splitting and analyzing the code structure; in fact, in the daily development process, most of the complex logic of the code is in parts 1 and 2, and part 2 has logic that calls each other, and various auxiliary functions are mixed with each other, and slowly Making the code more and more complex and difficult to read.

Statements and Definitions

We can encapsulate the complexity of parts 1 and 2, and define a standard and clean structure. As

  • The original codes 1 and 2 **polymerAction**were aggregated through calls, and the state and actions/method declarations were put together; and then **const [state, actions, shareVars] = usePolymerActionState(countActions)**the data and actions/methods were exposed to the outside.
  • Originally, the three parts of encapsulated hooks **usePolymerActionState**were called using exposed methods and followed the normal calling logic .
  • In the view, hooks are used to encapsulate methods normally, **return**expose **usePolymerActionState**data and methods, and call logic normally.

It can be seen that the core part is to encapsulate state and action together with high cohesion , and organize the code structure through objects, and objects can be combined to organize more complex code logic and structure.
From a view perspective, only exposed methods are called.
To sum up, according to the above method, the maintainability of the project can be improved and the code structure can be unified.

usage

/** @jsx createElement */ 
import { createElement, useEffect, useState, useRef, useMemo } from  'react' ;
\
export  default  function  Realtimetrendinghotels ( props ) {
   const { gdc, mds, pageUtils } = props;
  

  return ( < CustomComponent
   
  /> );
}
import { createElement, useEffect, useState, useRef, useMemo } from  'react' ; `
import {initHooksAction} from './hooks';
function CustomComponent(props) {
  const [
    count, {setCounts, sendLog}
  ] = initHooksAction();

 return (
   <View style={{width: 100, height: 100, backgroundColor: 'red'}} onClick={() => {
   setCounts('Data entered');
 }}>
   
   <Text>{count}</Text>
</View>
 
 
 );

}

initHooksActionYou can get data and methods; follow normal logic;

const countActions = polymerAction ({
   count : 0
}, {
  setCounts ( {state, setState}, params ) {
     setState ({
       count : ++state. count
    })
    console.log ( params )
  },
  fetch ( {state, setState}, count ) {
     console . log ( `Interface request buried point ${
      count} ` )
  },
  sendLog ( {state, setState, actions}, count ) {
    actions. fetch (count)
     console . log ( `Send relevant points ${
      count} ` )
  },
}, {});

function  initHooksAction () {
   const [state, actions, shareVars] = usePolymerActionState (countActions);
   useEffect ( () => {
     sendLog (state. count );
  }, [state. count ])
   return [state. count , actions, shareVars]
}
  • polymerAction: declare state, actions, shareVar;
  • usePolymerActionState: The bottom layer will override the actions method and shareVar data.
    • The returned data corresponds to polymerActionthe data and methods declared there
  • initHooksAction: encapsulates hooks logic
    Advanced usageSplit/merge actionsconst infiniteScrollAction = polymerAction ({ isLoadingShow : false , isLoadingError : false , isEmptyData : false , }, { showLoading ( { state, setState, shareVars, actions } ) { setState ({ isLoadingShow : true , isLoadingError : false , isEmptyData : false }); }, closeLoading ( { state, setState, shareVars, actions } ) { setState ({ isLoadingShow : false }); shareVars.throttleTarget = true ;​ }, …, }, { throttleTarget : true , }); const handleAction = polymerAction ({},{ /** * Refresh interface */ onRefreshList ( { state, setState, shareVars, actions } ) { …. }, },{}) const scrollListAction = polymerAction ({ cityList : [], recommendList : [], isCityListShow : false , }, { initListParam ( { state, setState, shareVars, actions } ) { shareVars.pageNo = 0 ;​ shareVars.dataVersion = 0 ;​ }, exp ( { state, setState, shareVars, actions }, data ) { const {cityName, cityCode} = shareVars. cityData ; let shidsArr = []; if (data[ 0 ] && data[ 0 ]. hotHotelList ) { shidsArr = hotCityListShids (data); sendUT. exp (cityName, shidsArr[ 0 ]. join ( ‘/’ ), shidsArr[ 1 ]. join ( ‘/’ )); } else { shidsArr = shids (data); sendUT. exp (cityName, ” , shidsArr. join ( ‘/’ )); } }, …, }, { pageNo : 0 , dataVersion : 0 , cityData : { cityName : ” , cityCode : ” , } }); function initEffect ( param ) { const [state, action] = usePolymerActionState ( mergePolymerAction (scrollListAction,infiniteScrollAction,handleAction)); … … return [state, action] } **mergePolymerAction**Multiple actions,scrollListAction , infiniteScrollAction, can handleActionbe combined; in this way, actions can be split arbitrarily .
    APIuseSetStateThe usage of Hooks that manage object type state is basically the same as this.setState of class components.
const [state,setState] = useSetState ({
  hehe : 1 ,
  aaa : 1
});
//Modify 
setState ({
 aaa : 2 
})


getAction

Get actions from polymerAction

const handleAction = polymerAction ({},{
   /**
   * Refresh interface
   */ 
  onRefreshList ( { state, setState, shareVars, actions } ) {
  ....
  },
},{});

const handle = getAction (handleAction);

console .log ( handle);

,{
  /**
   * Refresh interface
   */ 
  onRefreshList ( { state, setState, shareVars, actions } ) {
  ....
  },
}

polymerAction

Generate action collection

const scrollListAction = polymerAction ({
   cityList : [],
   recommendList : [],
   isCityListShow : false ,
}, {
  initListParam ( { state, setState, shareVars, actions } ) {
    shareVars.pageNo = 0 ;​
    shareVars.dataVersion = 0 ;​
  },
  ...,
}, {
  pageNo : 0 ,
   dataVersion : 0 ,
   cityData : {
     cityName : '' ,
     cityCode : '' ,
  }
});
const [state,actions,shareVal] = polymerAction (stateObj,actionObj,shareValObj)

Params

parameterillustratetypedefault value
stateObjRequired, declare stateobject{}
actionObjRequired, declare methods and functionsobject{}
shareValObjOptional, pass in the default status valueboolean{}

Result

parameterillustratetype
statestatus valueobject
actionsOperation setActions
shareValshared variablesobject

actionObj

const handleAction = polymerAction ({},{
   /**
   * Refresh interface
   */ 
  onRefreshList ( { state, actions, shareVars, setState, setShareVars }, param ) {
  ...
  },
     /**
   * The interface reports an error, refresh the interface
   */ 
  onRefreshListError ( { state, setState, shareVars, actions } ) {
    actions.getList ( true ) ;
  },
},{});
parameterillustratetype
stateGet stateObj**object**
actionsGet actionObj**object**
shareVarsGet shareValObj**object**
setStateset state**({}) => void**
setShareVarsSet shareVal**({}) => void**

usePolymerActionState

According to the input 

action, it is converted into something that can change the page.**PolymerActionState**

function  initEffect ( param ) {
   const [state, actions] = usePolymerActionState (scrollListAction);
  ...
  ...
  return [state, action]
}
const [state, actions,shareVal] = usePolymerActionState (polymerAction);

Params

parameterillustratetype
polymerActionRequired, statement polymerActionStatecollection**Array**

Result

parameterillustratetype
statestatus value**object**
actionsOperation set**object**
shareValshared variables**object**

mergePolymerAction

Merge multiple

**polymerAction**

mergePolymerAction (scrollListAction,infiniteScrollAction,handleAction)

code

let useState = null ;
 let useRef = null ;
 let useMemo = null ;
 function  useSetState ( initData ) {
   const [state, setState] = useState (initData);
   const  dispatch = ( next ) => {
     if ( typeof next === ' object' ) {
       setState ( ( pre ) =>  Object . assign ({}, pre, next));
    }
    else {
       setState (next);
    }
  };
  return [state, dispatch];
}

function  polymerAction ( state, action = {}, shareVar = {} ) {
   return [state, action, shareVar];
}

function  newActionData ( actions, states, shareVars, setState ) {
   let newAction = {};
   Object . keys (actions)
    . forEach ( ( name ) => {
       const old = actions[name];
       if ( typeof old === 'function' ) {
         // Rewrite the actions method 
        newAction[name] = function ( ...arg ) {
           return old . call ( null , {
             state : states,
            shareVars,
            actions : newAction,
             setState ( param, fn = () => {} ) {
               setState (param);
               fn (param);
            },
            setShareVars ( param ) {
              shareVars = Object . assign (shareVars, param);
            },
          }, ...arg);
        };
      }
    });
  return newAction;
}


// Function  associated with hooks usePolymerActionState ( param ) {
   const [state, action = {}, shareVar = {}] = param;
   const actions = action;
   // Object.assign({}, xxx) Multiple loading duplicate components are generated Corresponding data to prevent data from overwriting each other 
  const [states, setState] = useSetState ( Object . assign ({}, state));
   // Generate new shared variables 
  const shareVars =   useMemo ( () => ( Object . assign ({} , shareVar)), []) ;
  shareVars. updateAfterState = states;
   const newAction =   useMemo ( () => ( newActionData (actions, states, shareVars, setState)), [action, states, shareVars])

  return [states, newAction, shareVars];
}

function  getAction ( polymer ) {
   return polymer[ 1 ];
}

function  mergePolymerAction ( action1, ...res ) {
   const actions = action1. map ( function ( val, index ) {
     let resAction = {};
    res. forEach ( ( action ) => {
       Object . assign (resAction, action[index]);
    });
    return  Object . assign ({}, val, resAction);
  });
  return actions;
}


function  injectState ( newUseState, newUseRef, newUseMemo ) {
   if (!newUseState || !newUseMemo) {
     console . warn ( `Please pass in useState and useMemo in moduleInit in the module, such as:
    moduleInit({ gdc,mds,pageUtils})
    (useState, useEffect, useRef, useMemo);` );
     return
  }
  useState = newUseState;
  useRef = newUseRef;
  useMemo = newUseMemo;
}

export {
  useSetState,
  getAction,
  polymerAction,
  usePolymerActionState,
  mergePolymerAction,
  injectState
};

github

https://github.com/NoahsDante…