Public account: wechat search front end tool person; Take more dry goods

The React ecosystem has spawned many state management wheels;

How to choose state management during development is also a bit tricky;

Here is a simple comparison of what I understand and used in the project (react-redux, Recoil, useContext) for reference only.

First, personal advice

React-Redux

  • Can be familiar withReact-ReduxArchitecture component ideas, which I find useful for everyday development,ReduxThe first choice for severe patients
  • Shared state many and large individuals feel that can be prioritized, combinedcombineReducers

Recoil

  • Daily development is fully adequate, simple to use, easy to use, commonly usedAPINot much… , very sweet
  • State rendering causes the component to rerender the block,RecoilHave to do optimization, performance is still very Ok;

useContext

  • Function component development is preferred as a local shared state; The shared state of the current page is also handed over to global state management, which is definitely not consistent

Own daily development

  • Global state ManagementReact-ReduxorRecoil(Preferred)
  • Local stateuseContext, the combination of the two;

Of course, there are many excellent state management plug-ins, MobX, HOx, etc., which I won’t discuss much if I don’t use them myself.

The following introduction is wrong, or there is a better way, please leave a message, thank you big guy first

React,react, flutter and electron are all used in daily development, so my insights are not deep. I just post the daily development for reference only

Second, the React – story

Personally, I don’t think the React-Redux has obvious advantages over other wheels at present.

Since I came from Redux, there were not many options for wheels in the early stage, so the old project always used React-Redux and was not replaced in the reconstruction.

Disadvantages:

  • Syntax is not concise, especially without hook Api;
  • Sharing state between components can only be done by promoting state to their common ancestor, but doing so can result in rerendering a huge tree of components

Advantages:

The React-Redux architecture component idea is a good one for me, and works well with a granularity of component separation during development;

React-redux divides all components into two broad categories

  • The UI components (presentational component)
  1. Only responsible forUIRender without any business logic
  2. No state (that is, not usedstateThis variable)
  3. All data is defined by parameters (props) to provide
  4. Without using anyReduxAPI
  5. Also known asPure component, that is, pure functions, purely parameters determine its value, without any side effects
  • Container components (container component)
  1. Responsible for managing data and business logic, but not responsibleUIIn the present
  2. With internal state, can be usedReduxAPI
  3. Contains input logic: external data (i.estateObject) how to convert toUIComponent parameters
  4. Output logic: How do actions issued by the user becomeActionFrom objects,UIComponent outgoing

UIComponent is responsible forUIContainer components are responsible for managing data and logic

React-ReduxSpecifies that all UI components are provided by the user, while container components are provided byReact-ReduxAutomatic generation. In other words, the user takes care of the visual layer, leaving state management to it

If a component already existsUIIf there is business logic, then split it up: there is a container component on the outside and a container component on the insideUIComponents. The former is responsible for communicating with the outside world, passing the data to the latter, who renders the view

Code snippet

Import {createStore} from 'redux'; import {createStore} from 'redux'; export const Types = { CHANGE_DEVELOP: 'CHANGE_DEVELOP', CHANGE_LANGUAGE: 'CHANGE_LANGUAGE' } const onChangeDevelop = <T = string>(val: T) => { return { type: Types.CHANGE_DEVELOP, payload: val } } const onChangeLanguage = <T = string>(val: T) => { return { type: Types.CHANGE_LANGUAGE, payload: Val}} const baseState = {language: 'zh', developer: 'front-end'} interface IAction {type: string, payload: any } const reducer = (state = baseState, action: IAction) => { switch (action.type) { case Types.CHANGE_LANGUAGE: return { ... state, language: action.payload}; case Types.CHANGE_DEVELOP: return { ... state, developer: action.payload }; default: return state; } } const configureStore = () => createStore(reducer) export default configureStore; TSX import {Provider} from 'react-redux' import configureStore from './store/index' const store = configureStore() ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') ); TSX import {useDispatch, useSelector} from 'react-redux' const Header = () => { const dispatch = useDispatch() const developer = useSelector((state) => state.developer) const onChangeDeveloper = ()=> { dispatch({ type: Types.CHANGE_DEVELOP, developer: 'Modified developer'})}}Copy the code

Third, Recoil

advantage

I’m quoting from Recoil documentation, blah, blah, blah, blah, blah, blah

  • React provides the React state management library. Use the React state management library.

  • Defines an directed graph that is orthogonal and naturally connected to your React tree. The change in state starts at the vertex of the graph (we call it atom) and flows through the pure function (we call it selector) to the component

  • Using Recoil will create a data flow diagram for you, from Atom (shared state) to selector (pure function) to the React component. Atom is a unit of state to which a component can subscribe. Selector can change this state synchronously or asynchronously.

  • We can define apis that do not require template code, and the shared state has a get/set interface as simple as the React local state (although we can also encapsulate it using reducer, etc., if necessary).

  • We now have the possibility of compatibility with Concurrent mode and other React new features.

  • The definition of state is progressive and distributed, which makes code fragmentation possible.

  • Their local state can be replaced with derived data without modifying the corresponding components.

  • Derived data can be switched between synchronous and asynchronous without modifying the corresponding component.

  • Navigation can be treated as a first-class concept, and transitions of state can even be coded into links.

  • You can easily persist the state of the entire application in a traceable manner, and the persistent state is not lost as the application changes

Code snippet

Import React from 'React '; // store/index.js // import { atom, selector, } from 'recoil'; // Recoil key set const KEYS = {COMMON_STATE: 'commonState' PRODUCT_COUNT: 'productCount' } interface IBaseStore { language: string, developer: string, email: string, children: React.ReactNode[] | React.ReactNode } export const commonState = atom<IBaseStore>({ key: KEYS.COMMON_STATE, default: { language: 'zh', developer: 'laisheng', children: [], email: '[email protected]' } }) export const productCount = selector({ key: KEYS.PRODUCT_COUNT, get: ({get}) => { return get(commonState) }, set:({set, reset, get}, newValue) => { console.log(newValue) } }) // App.tsx import { RecoilRoot } from 'recoil'; const App: React.FC<AppProps> = () => { return ( <RecoilRoot> <Router> <RouterPage /> </Router> </RecoilRoot> ) } export default TSX import {useRecoilState, useRecoilValue} from 'recoil' import { commonState } from '@/store' const Header = () => { const [comState, setComState] = useRecoilState(commonState); setComState({ ... ComState, developer: 'Update tool person'})}Copy the code

Four, useContext

This is a buff that comes with react-hooks and is quite ok

There is no further explanation for this, so let’s go to the code snippet

// Home. TSX // The following types involve other places to import, Import React, {createContext, useMemo, useContext, useEffect, useReducer, useRef, useState, memo, useCallback } from 'react'; interface IHomeContext<T> { state: T, dispatch: any } interface IState { communityId: string | number, communityName: string, macAddress: string | number, doorControlName: string, } const homeState = { communityId: '', communityName: '', macAddress: '', doorControlName: '' } const HomeContext = createContext<IHomeContext<IState>>({ state: Const onChangeHomeState = (state: any, data: any): const onChangeHomeState = (state: any, data: any) IState => {for (let key in data) {// Avoid useContext store undefined fields if (key in state) state[key] = data[key]} return {... state } } const Home: React.FC = () => { const [state, dispatch] = useReducer(onChangeHomeState, homeState) return ( <HomeContext.Provider value={{ state: useMemo(() => state, [state]), dispatch }}> <div className="home-container"> <main> <Header /> ... </main> </div> </ homecontext.provider >)} // Use const Header = () => {const {state, Dispatch} = useContext(HomeContext) // Age, address onChangeHomeState CommunityId dispatch({'communityId': 13, age: 18, address: 'shenzhen'})}Copy the code