Contents
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;
- Declare variable data /shared variable declaration, state declaration/let xxx= xxx/useState
- Method declaration /function xx () {} /action/dispatch
- Method call /xx()/action()/dispatch()
- 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:
- : Mainly declaring data, including useState/let xxx = 11;
- : Declaring functions and methods will involve modifying
**setcounts**
and using data**sendLogcount**
;- There will be some auxiliary methods in modification and use
fetch
to execute the corresponding logic;
- There will be some auxiliary methods in modification and use
- 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> ); }
initHooksAction
You 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
polymerAction
the data and methods declared there
- The returned data corresponds to
- 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
, canhandleAction
be 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
parameter | illustrate | type | default value |
---|---|---|---|
stateObj | Required, declare state | object | {} |
actionObj | Required, declare methods and functions | object | {} |
shareValObj | Optional, pass in the default status value | boolean | {} |
Result
parameter | illustrate | type |
---|---|---|
state | status value | object |
actions | Operation set | Actions |
shareVal | shared variables | object |
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 ) ; }, },{});
parameter | illustrate | type |
---|---|---|
state | Get stateObj | **object** |
actions | Get actionObj | **object** |
shareVars | Get shareValObj | **object** |
setState | set state | **({}) => void** |
setShareVars | Set 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
parameter | illustrate | type |
---|---|---|
polymerAction | Required, statement polymerActionState collection | **Array** |
Result
parameter | illustrate | type |
---|---|---|
state | status value | **object** |
actions | Operation set | **object** |
shareVal | shared 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 };