Build a Simple Redux from Scratch and Integrate It with React
This article explains Redux’s core concepts, demonstrates how to implement a basic createStore function in JavaScript, and shows how to integrate it with React using a custom Provider and connect higher‑order component for state sharing across components.
Redux is a popular state management tool that stores the entire application state in a single place for centralized management. This article implements a simple Redux from scratch.
Core concepts of Redux
The entire application state is stored in a single store.
The only way to change state is by dispatching actions.
Reducers describe how actions transform the state.
Store API
getState() – retrieve the current state.
dispatch(action) – update the state.
subscribe(listener) – register a listener.
The function returned by subscribe can unsubscribe the listener.
Implementing createStore
const createStore = (reducer, preloadedState) => {
let state = preloadedState;
const listeners = new Set();
// dispatch(action) updates state
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
// getState() returns state
const getState = () => state;
// subscribe registers a listener
const subscribe = (listener) => {
listeners.add(listener);
return unsubscribe(listener);
};
// unsubscribe removes a listener
const unsubscribe = (listener) => () => {
listeners.delete(listener);
};
return { dispatch, subscribe, getState };
};Using the store
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
};
const store = createStore(reducer);
const unsubscribe = store.subscribe(() => {
const state = store.getState();
console.log(state.count);
});
store.dispatch({ type: "increment" });
unsubscribe();Integrating with React
The store can be used in React components; when the store changes, components are forced to re‑render.
const Counter = () => {
const [, forceUpdate] = React.useState();
useEffect(() => {
const unsubscribe = store.subscribe(() => {
forceUpdate({});
});
return () => {
unsubscribe();
};
}, []);
return (
<div onClick={() => store.dispatch({ type: "increment" })}>
{store.getState()?.count || 0}
</div>
);
};Simple React‑Redux implementation
First, define a Provider component using React Context to share the store.
const ReduxContext = React.createContext();
const Provider = ({ store, children }) => {
const contextValue = useMemo(() => ({ store }), [store]);
return (
<ReduxContext.Provider value={contextValue}>
{children}
</ReduxContext.Provider>
);
};Then, create a connect higher‑order component that maps store state and dispatch to component props and forces a re‑render when the store updates.
const connect = (mapStateToProps, mapDispatchToProps) => {
return (Component) => {
return (props) => {
const [, forceUpdate] = useState({});
const { store } = useContext(ReduxContext);
const stateToProps = mapStateToProps(store.getState());
const dispatchToProps = mapDispatchToProps(store.dispatch, props);
useEffect(() => {
const unsubscribe = store.subscribe(() => {
forceUpdate({});
});
return () => {
unsubscribe();
};
}, [store]);
return <Component {...props} {...stateToProps} {...dispatchToProps} />;
};
};
};Usage example:
const Counter = (props) => (
<div onClick={props.onClick}>{props.count}</div>
);
const CounterWrap = connect(
state => ({ count: state.count }),
dispatch => ({
onClick: () => {
dispatch({ type: "increment" });
}
})
)(Counter);
const App = () => (
<Provider store={store}>
<CounterWrap />
</Provider>
);Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
