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 with
React-Redux
Architecture component ideas, which I find useful for everyday development,Redux
The first choice for severe patients - Shared state many and large individuals feel that can be prioritized, combined
combineReducers
Recoil
- Daily development is fully adequate, simple to use, easy to use, commonly used
API
Not much… , very sweet - State rendering causes the component to rerender the block,
Recoil
Have 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 Management
React-Redux
orRecoil
(Preferred) - Local state
useContext
, 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
)
- Only responsible for
UI
Render without any business logic- No state (that is, not used
state
This variable)- All data is defined by parameters (
props
) to provide- Without using any
Redux
的API
- Also known as
Pure component
, that is, pure functions, purely parameters determine its value, without any side effects
- Container components (
container component
)
- Responsible for managing data and business logic, but not responsible
UI
In the present- With internal state, can be used
Redux
的API
- Contains input logic: external data (i.e
state
Object) how to convert toUI
Component parameters- Output logic: How do actions issued by the user become
Action
From objects,UI
Component outgoing
UI
Component is responsible forUI
Container components are responsible for managing data and logic
React-Redux
Specifies that all UI components are provided by the user, while container components are provided byReact-Redux
Automatic generation. In other words, the user takes care of the visual layer, leaving state management to it
If a component already existsUI
If there is business logic, then split it up: there is a container component on the outside and a container component on the insideUI
Components. 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