Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize State sharing based on React Hooks

2025-03-04 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces how to achieve React Hooks-based state sharing, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, let the editor take you to understand it.

Realization of State sharing based on React Hooks

State sharing between React components is an old problem, and there are many solutions, such as Redux, MobX, and so on. These solutions are very professional and have stood the test of time, but I think they are not suitable for some less complex projects and will introduce some additional complexity.

In fact, most of the time, I don't want to define mutation and action, I don't want to set a layer of context, let alone write connect and mapStateToProps;. What I want is a lightweight, simple state sharing solution that is easy to quote and use.

With the birth and popularity of Hooks, my idea came true.

Then I introduce the solution I am currently using, which combines Hooks with publish / subscribe model to achieve a simple and practical state sharing scheme. Because there is not much code, the complete implementation is given below.

Import {Dispatch, SetStateAction, useCallback, useEffect, useReducer, useRef, useState,} from 'react' / * @ see https://github.com/facebook/react/blob/bb88ce95a87934a655ef842af776c164391131ac/packages/shared/objectIs.js * inlined Object.is polyfill to avoid requiring consumers ship their own * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is * / function is (x: any, y: any): boolean {return (x = y & & (x! = = 0 | | 1 / x = = 1 / y)) | (x! = = x & & y! = = y) } const objectIs = typeof Object.is = 'function'? Object.is: is;/** * @ see https://github.com/facebook/react/blob/933880b4544a83ce54c8a47f348effe725a58843/packages/shared/shallowEqual.js * Performs equality by iterating through keys on an object and returning false * when any key has values which are not strictly equal between the arguments. * Returns true when the values of all keys are strictly equal. * / function shallowEqual (objA: any, objB: any): boolean {if (is (objA, objB)) {return true;} if (typeof objA! = = 'object' | | objA = null | | typeof objB! = =' object' | | objB = null) {return false;} const keysA = Object.keys (objA); const keysB = Object.keys (objB); if (keysA.length! = = keysB.length) {return false } / / Test for A's keys different from B. For (let I = 0; I

< keysA.length; i++) { if ( !Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]]) ) { return false; } } return true;}const useForceUpdate = () =>

UseReducer (() = > ({}), {}) [1] as VoidFunction;type ISubscriber = (prevState: t, nextState: t) = > void;export interface ISharedState {/ * * get data statically. It is suitable to use * / get: () = > T; / * * to modify the data and give it a new value * / set: Dispatch; / * * (shallow) merge and update the data * / update: Dispatch / * * hooks method is suitable for use in the component. When the data changes, the component will be automatically re-rendered * / use: () = > T; / * * change of subscription data * / subscribe: (cb: ISubscriber) = > () = > void; / * * change of unsubscription data * / unsubscribe: (cb: ISubscriber) = > void / * * sift out some state * / usePick (picker: (state: t) = > R, deps?: readonly any []): r;} export type IReadonlyState = Omit;/** * create a state that can be shared between different instances * @ param initialState initial data * / export const createSharedState = (initialState: t): ISharedState = > {let state = initialState; const subscribers: ISubscriber [] = [] / / changes in subscription state const subscribe = (subscriber: ISubscriber) = > {subscribers.push (subscriber); return () = > unsubscribe (subscriber);}; / / changes in unsubscribing state const unsubscribe = (subscriber: ISubscriber) = > {const index = subscribers.indexOf (subscriber); index >-1 & subscribers.splice (index, 1);}; / / get the latest state const get = () = > state / / change state const set = (next: SetStateAction) = > {const prevState = state; / / @ ts-ignore const nextState = typeof next = = 'function'? Next (prevState): next; if (objectIs (state, nextState)) {return;} state = nextState; subscribers.forEach ((cb) = > cb (prevState, state));}; / / get the current hooks usage of state const use = () = > {const forceUpdate = useForceUpdate (); useEffect () = > {let isMounted = true / / update the component immediately after mounting to avoid not being able to use the first update data forceUpdate (); const un = subscribe () = > {if (! isMounted) return; forceUpdate ();}); return () = > {un (); isMounted = false;};}, []); return state;} Const usePick = (picker: (s: t) = > R, deps = []) = > {const ref = useRef ({}); ref.current.picker = picker; const [pickedState, setPickedState] = useState (() = > ref.current.picker (state),); ref.current.oldState = pickedState; const sub = useCallback (() = > {const pickedOld = ref.current.oldState; const pickedNew = ref.current.picker (state) If (! shallowEqual (pickedOld, pickedNew)) {/ / avoid that pickedNew is a function setPickedState (() = > pickedNew);}}, []); useEffect () = > {const un = subscribe (sub); return un;}, []); useEffect (() = > {sub ();}, [... deps]); return pickedState;} Return {get, set, update: (input: Partial) = > {set ((pre) = > ({... pre,... input,});}, use, subscribe, unsubscribe, usePick,};}

With createSharedState, the next step is to easily create a shareable state and use it in a straightforward way in your components.

/ / create a state instance const countState = createSharedState (0); const A = () = > {/ / get responsive data in the component using hooks const count = countState.use (); return A: {count};}; const B = () = > {/ / use the set method to modify data return countState.set (count + 1)} > Add;} Const C = () = > {return ({/ / use get method to obtain data console.log (countState.get ());}} > Get);}; const App = () = > {return ();}

For complex objects, it also provides a way to listen for data changes in a specified part of the component to avoid redundant render caused by other field changes:

Const complexState = createSharedState ({a: 0, b: {c: 0,},}); const A = () = > {const a = complexState.usePick ((state) = > state.a); return A: {a};}

However, it is generally recommended to use combinatorial derivation to derive a complex object from multiple simple states. In addition, sometimes we need a calculation result based on the original data, so a way to derive the data is also provided here.

By listening to the data source by showing declared dependencies, and then passing in the computational function, you can get a responsive derivative result.

/ * status derivation (or computed) * ```ts * const count1 = createSharedState (1); * const count2 = createSharedState (2); * const count3 = createDerivedState ([count1, count2], ([N1, N2])) = > N1 + N2) * ```* @ param stores * @ param fn * @ param initialValue * @ returns * / export function createDerivedState (stores: IReadonlyState [], fn: (values: any []) = > T, opts?: {/ * whether to synchronize the response * @ default false * / sync?: boolean;},): IReadonlyState & {stop: () = > void;} {const {sync} = {sync: false,... opts} Let values: any [] = stores.map ((it) = > it.get ()); const innerModel = createSharedState (fn (values)); let promise: Promise | null = null; const uns = stores.map ((it, I) = > {return it.subscribe ((_ old, newValue) = > {values [I] = newValue; if (sync) {innerModel.set (() = > fn (values)); return } / / Asynchronous update promise = promise | | Promise.resolve () .then (() = > {innerModel.set (() = > fn (values)); promise = null;});});}) Return {get: innerModel.get, use: innerModel.use, subscribe: innerModel.subscribe, unsubscribe: innerModel.unsubscribe, usePick: innerModel.usePick, stop: () = > {uns.forEach ((un) = > un ());},};}

At this point, the introduction of the implementation of the state sharing party based on Hooks is over.

In recent projects, I have chosen the above methods for scenarios that require state sharing. It has always been smooth to use the same set of implementation in both Web projects and Mini Program Taro projects.

Feeling of use

Finally, several characteristics of the current approach are summarized:

1. It is easy to implement and does not introduce other concepts. It is only based on Hooks and combined with publish / subscribe model. React-like scenarios can be used, such as Taro.

two。 It is easy to use, because there is no other concept, you can get the reference of state by calling the create method directly, and the binding of components and data is completed by calling the use method on the state instance.

3. Type-friendly, you don't need to define extra types when creating state, and you can derive types automatically when using them.

4. The "closure trap" of Hooks is avoided, because references to state are constant, and the latest values can always be obtained through the get method of state:

Const countState = createSharedState (0); const App = () = > {useEffect () = > {setInterval (()) = > {console.log (countState.get ());}, 1000);}, []); / / return...}

5. Sharing among multiple React applications is directly supported, and it is easy to have multiple React applications when using some pop-up boxes:

Const countState = createSharedState (0); const Content = () = > {const count = countState.use (); return {count};}; const A = () = > ({Dialog.info ({title: 'Alert', content:,});}} > open)

6. Support for obtaining / updating data in scenarios outside the component

7. There are great limitations in the SSR scenario: state is created in bits and pieces, and the life cycle of state does not follow React applications, which makes it impossible to write SSR application code in an isomorphic way

Thank you for reading this article carefully. I hope the article "how to achieve React Hooks-based state sharing" shared by the editor will be helpful to everyone. At the same time, I also hope that you will support and pay attention to the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report