惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel The physics behind spring animations - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel React sub-components - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel
Maxime Heckel · 2018-12-05 · via Maxime Heckel's Blog

There’s been a lot of hype recently about React Hooks and what they allow developers to achieve. Indeed, in the near future, we will be able to rely on a single React pattern to build pretty much anything we want. As of today, React consist of a lot of patterns, if not too many for some people: Stateful Classes, Functional components, Higher Order Components and render callbacks to mention just a few.
The React core team expressed several months ago their desire to slowly phase out React Classes. Hooks, along with Suspense, which I talked about in a previous post, are the main building blocks of this plan.

In this post, however, rather than focusing on how hooks impact React components themselves, I want to go a bit further and showcase how they can be used, in conjunction with the already existing Context API, to build a very basic implementation of Redux. The example I will provide covers the basics functionality of Redux for global state management.

For this example, we will consider a simple application. It will display some message that can be fetched through a Redux action FETCH_DATA which can be triggered by clicking on a button.

Provider and reducers

Let’s consider the following reducers:

Example of a classic reducer used with Redux

2

export const initialState = {

6

const reducer = (state, action) => {

7

const reduced = { ...state };

21

export default reducer;

As we can see, this is the kind of reducers we’re used to seeing in any Redux based application. The objective is to have the same reducers working for our implementation of Redux.

First step: Defining our **Provider**This will be the core of our reimplementation of Redux. The Redux Provider works quite like a basic React Context Provider, so we can base our work on the Context API. Our store Provider will wrap our app and let it access our store object at any level. Here’s how it looks like:

Implementation of a store provider using the React Context API

2

import React, { createContext, useReducer, useContext } from 'react';

3

import reducer, { initialState } from './reducer';

5

const Store = createContext();

7

const Provider = ({ children }) => {

8

const store = createStore(reducer, initialState);

9

return <Store.Provider value={store}>{children}</Store.Provider>;

12

export { Store, Provider };

Second step: **createStore **We can see above the mention of the createStore function. If you’re familiar with Redux this should ring a bell. This function takes our reducer, and the initial state object of our app returns an object with 2 essential items that are injected into the app through our Provider:

  • dispatch: the function that lets us dispatch Redux action

  • state: the object containing the global state of our app.

To reimplement this function in our example, let’s use the new React hooks. React has a very handy pre-built hook called useReducer which actually returns these 2 items stated above:

createStore implementation

2

const createStore = (reducer, initialState) => {

3

const [state, dispatch] = useReducer(reducer, initialState);

4

return { state, dispatch };

We now have all the elements for our implementation of Redux to work! Below you will see the code of our basic app that is using the examples above to dispatch actions and get some data from our store.

Small application using our basic reimplementation of Redux using Context and Hooks

1

import React, { useContext } from 'react';

2

import { Store, Provider } from './store';

4

const Data = (props) => {

5

const { state, dispatch } = useContext(Store);

6

return <div>{props.data}</div>;

10

const Controls = () => {

11

const { state, dispatch } = useContext(Store);

17

dispatch({ type: 'FETCH_DATA', payload: 'Hello world!' })

22

<button onClick={() => dispatch({ type: 'RESET_DATA', payload: null })}>

34

<header className="App-header">

35

<h1>React {React.version}</h1>

However, we can see that although the constructs we came up with are quite similar to the ones of Redux, the way it’s used within an app is not quite the same. This is why I wanted to push the example a bit further and reimplement the connect Higher Order Component.

Rebuilding the Connect HoC

For this part, we want to achieve the following:

Example of a component using the connect HoC

2

const mapStateToProps = (state, props) => ({

3

message: `${state.data} ${props.extra}`,

6

const mapDispatchToProps = (dispatch) => ({

7

get: () => dispatch({ type: 'FETCH_DATA', payload: 'Hello world!' }),

8

reset: () => dispatch({ type: 'RESET_DATA', payload: 'null' }),

11

const ConnectedData = connect(mapStateToProps, mapDispatchToProps)(Data);

Given the code above, our connect HoC must take 2 optional arguments: a mapStateToProps function and a mapDispatchToProps function. It will then inject the following items as props for the wrapped component:

  • the dispatch function

  • the objects returned by mapStateToProps and mapDispatchToProps

Implementation of the connect HoC from Redux based on the useContext hook

2

const connect = (mapStateToProps = () => {}, mapDispatchToProps = () => {}) => (

6

const { dispatch, state } = useContext(Store);

10

{...mapStateToProps(state, props)}

11

{...mapDispatchToProps(dispatch)}

With this implementation of connect, we now have a more familiar way to access the state from our components.

Going even further by adding middleware support

One other thing that would be nice to have in our reimplementation of Redux would be some support for middlewares. In this part will try to emulate how middlewares work in Redux, and try to end up having a similar implementation.

**How do middlewares currently work?
**In a nutshell, middlewares are enhancements to the dispatch function.
Middlewares take a store object as an argument, which contains a getState function and a dispatch function, and are then composed to finally give us an enhanced dispatch. By looking in the Redux codebase we can see that this enhanced dispatch function is a curried function where the middlewares are “composed” and then applied to our dispatch.
Compose here means that instead of having to write for example f1(f2(f3(f4))) we can simply write compose(f1,f2,f3,f4).

Note: This short summary and the code implementation below are based on my own research and on this article.

Implementation of middleware support for our createStore function

2

const compose = (...funcs) => (x) =>

3

funcs.reduceRight((composed, f) => f(composed), x);

5

const createStore = (reducer, initialState, middlewares) => {

6

const [state, dispatch] = useReducer(reducer, initialState);

8

if (typeof middlewares !== 'undefined') {

10

const middlewareAPI = {

11

getState: () => state,

12

dispatch: (action) => dispatch(action),

14

const chain = middlewares.map((middleware) => middleware(middlewareAPI));

15

const enhancedDispatch = compose(...chain)(dispatch);

16

return { state, dispatch: enhancedDispatch };

19

return { state, dispatch };

We can now add a basic middleware to our createStore function. Here’s one that logs to the console any action that is dispatched:

Example of a custom middleware used with our Redux reimplementation

2

const customMiddleware = (store) => (next) => (action) => {

3

console.log('Action Triggered');

10

const Provider = ({ children }) => {

11

const store = createStore(reducer, initialState, [customMiddleware]);

12

return <Store.Provider value={store}>{children}</Store.Provider>;

Conclusion

Thanks to the Context API and the recently announced Hooks, we saw that it is now easy to rebuild Redux. Is it usable? Yes, as we saw in this post, we covered the main components of Redux (Store, connect, middlewares, etc) and use them in a small app. Can this replace react-redux? Probably not. Redux still has a lot more than what we covered in this article, like the Redux Devtools or the entire ecosystem of libraries that can enhance your app on top of Redux. While writing this post I’ve personally tried to add the redux-logger middleware to our example, it “worked” but I couldn’t make it print the correct “next state”(maybe because the useReducer hook is async since it’s based on setState ):

MaximeHeckel

I'm very close to have existing redux middlewares working with my implementation of Redux with React Hooks! (Here with Redux Logger, you can see the next state is not populated properly) https://t.co/HKHCPoMRUG

I'm very close to have existing redux middlewares working with my implementation of Redux with React Hooks! (Here with Redux Logger, you can see the next state is not populated properly) https://t.co/HKHCPoMRUG

but as you can see in this tweet, maybe I was just a bit too ambitious.

Want to continue working on this project or just hack on top of it? You can clone the repository containing the code featured in this article along with a basic application here.

What to read next?
If you want to read more about React or frontend development, you can check the following articles: