Not sure if this is a so-called "pub/sub" pattern or a form of a "pub/sub" pattern. I am trying to create a piece of shared state so that different components can subscribe to it and only gets updated when there is an update with that state.
const useForceUpdate = () => useReducer((state) => !state, false)[1];
const createSharedState = (reducer, initialState) => {
const subscribers = [];
let state = initialState;
const dispatch = (action) => {
state = reducer(state, action);
subscribers.forEach((callback) => callback());
};
const useSharedState = () => {
const forceUpdate = useForceUpdate();
useEffect(() => {
const callback = () => forceUpdate();
subscribers.push(callback);
const cleanup = () => {
const index = subscribers.indexOf(callback);
subscribers.splice(index, 1);
};
return cleanup;
}, []);
return [state, dispatch];
};
return useSharedState;
};
const initialState = 0;
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "set":
return action.count;
default:
return state;
}
};
const useCount1 = createSharedState(reducer, initialState);
const useCount2 = createSharedState(reducer, initialState);
const Counter = ({ count, dispatch }) => (
<div>
{count}
<button onClick={() => dispatch({ type: "increment" })}>+1</button>
<button onClick={() => dispatch({ type: "decrement" })}>-1</button>
<button onClick={() => dispatch({ type: "set", count: 0 })}>reset</button>
</div>
);
const Counter1 = () => {
const [count, dispatch] = useCount1();
return <Counter count={count} dispatch={dispatch} />;
};
const Counter2 = () => {
const [count, dispatch] = useCount2();
return <Counter count={count} dispatch={dispatch} />;
};
const Example = () => (
<>
<Counter1 />
<Counter1 />
<Counter2 />
<Counter2 />
</>
);
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<script type="text/babel">
const { useEffect, useReducer } = React;
const useForceUpdate = () => useReducer((state) => !state, false)[1];
const createSharedState = (reducer, initialState) => {
const subscribers = [];
let state = initialState;
const dispatch = (action) => {
state = reducer(state, action);
subscribers.forEach((callback) => callback());
};
const useSharedState = () => {
const forceUpdate = useForceUpdate();
useEffect(() => {
const callback = () => forceUpdate();
subscribers.push(callback);
const cleanup = () => {
const index = subscribers.indexOf(callback);
subscribers.splice(index, 1);
};
return cleanup;
}, []);
return [state, dispatch];
};
return useSharedState;
};
const initialState = 0;
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "set":
return action.count;
default:
return state;
}
};
const useCount1 = createSharedState(reducer, initialState);
const useCount2 = createSharedState(reducer, initialState);
const Counter = ({ count, dispatch }) => (
<div>
{count}
<button onClick={() => dispatch({ type: "increment" })}>+1</button>
<button onClick={() => dispatch({ type: "decrement" })}>-1</button>
<button onClick={() => dispatch({ type: "set", count: 0 })}>reset</button>
</div>
);
const Counter1 = () => {
const [count, dispatch] = useCount1();
return <Counter count={count} dispatch={dispatch} />;
};
const Counter2 = () => {
const [count, dispatch] = useCount2();
return <Counter count={count} dispatch={dispatch} />;
};
const Example = () => (
<>
<Counter1 />
<Counter1 />
<Counter2 />
<Counter2 />
</>
);
ReactDOM.render(<Example />, document.querySelector("#root"));
</script>
It seems to be working fine. My questions are:
useState
or useReducer
as one normally would do?Local state is perhaps the easiest kind of state to manage in React, considering there are so many tools built into the core React library for managing it. useState is the first tool you should reach for to manage state in your components. It can take accept any valid data value, including primitive and object values.
Why do you need React state management? React applications are built using components and they manage their state internally and it works well for applications with few components, but when the application grows bigger, the complexity of managing states shared across components becomes difficult.
In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called “lifting state up”. We will remove the local state from the TemperatureInput and move it into the Calculator instead.
React uses virtual DOM to display the details and Jquery is used to manipulate the DOM. So if you are using Jquery with React then you will be basically manipulating the Virtual DOM which is not recommended. Happy Coding!.
If you are new to these Hooks, check out How To Manage State with Hooks on React Components. The useReducer Hook is a good fit since you’ll need to update the most recent state on every action. Create a reducer function that adds a new item to a state array, then use the useReducer Hook to create a salad array and a setSalad function:
Global state in React is synonymous with libraries like Redux. If you ever needed to share state like the current route or data from an API with multiple components, then you may have reached for Redux yourself. Newer versions of React (16.3+) include a built-in way to share state, which means not having to pull in an external library.
To update data, you’ll need to use other state management tools such as Hooks. If you were collecting data for the same component, you’d use either the useState or useReducer Hooks. If you are new to these Hooks, check out How To Manage State with Hooks on React Components.
Newer versions of React (16.3+) include a built-in way to share state, which means not having to pull in an external library. This is known as the React Context API and it can be a bit tricky to learn. I hope to provide a simplified explanation and tutorial so that you can quickly add global state to any of your React apps.
useState
(DEMO) or as useReducer
(DEMO).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With