Git Product home page Git Product logo

ts-react-redux-hooks's Introduction

Type safe code splitting of Redux in React app (PoC)

Using Redux in a type safe manner can be a little tricky. For example, useSelector() and useDispatch() hooks are not strictly typed and you usually have to type them yourself. This may be OK if the store shape of your app is always the same. However it would be annoying if you code split Redux reducers and actions as described and have to type useSelector() and dispatch() precisely in each component depending on which reducers you use for the component.

Here, I implemented useReducerRegistry() hook which can be used to register reducers and retrieve typed useSelector() and useDispatch() hooks in return. To make useReducerRegistry() hook to be available, store must be created with reducerRegistryEnhancer() enhancer (If you are not familiar with Redux enhancer, please refer to the official Redux document).

The implementation of useReducerRegistry() and reducerRegistryEnhancer() can be found here. This branch hosts the working example (you can try it by cloning and run yarn install and yarn start).

The following code is the brief summary of how to use these APIs.

// store.ts
import {
  reducerRegistryEnhancer,
  useReducerRegistry as _useReducerRegistry,
  UseReducerRegistry,
} from './react-redux-code-split'
import reducer1 from './reducer1'
import reducer2 from './reducer2'
import { applyMiddleware, createStore, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'
import thunk from 'redux-thunk'

// Initial reducers
const initialReducers = { reducer1, reducer2 }

// Initial state
const InitialState = { /* ... */ }

// Create Store
export const store = createStore(
  combineReducers(initialReducers),
  initialState,
  // It is easy to compose reducerRegistryEnhancer() with the other enhancers
  composeWithDevTools(
    applyMiddleware(thunk),
    // Pass initialReducers to reducerRegistryEnhancer()
    reducerRegistryEnhancer(initialReducers)
  )
)

// Type useReducerRegistry as initialReducers has been already applied to the store.
// If there are no initial reducers, you can use useReducerRegistry directly without this additional typing 
export const useReducerRegistry: UseReducerRegistry<typeof initialReducers> = _useReducerRegistry

---

// MyComponent1.tsx
import { useReducerRegistry } from './store'
import additinalReducer from './additinalReducer'

const reducers = { additinalReducer }

const MyComponent1 = () => {
  // Register reducers and retrieve typed useSelector and useDispatch
  const { useSelector, useDispatch } = useReducerRegistry(reducers)
  // ...
}

---

// MyComponent2.tsx
import { useReducerRegistry } from './store'

const MyComponent2 = () => {
  // If you only need initialReducers in this component,
  // you can call useReducerRegistry without argument
  const { useSelector, useDispatch } = useReducerRegistry()
  // ...
}

Note

To take full advantage of these APIs, reducers must be typed strictly as the types of these APIs' return values depend on the reducers types. However, it seems reducers are not strictly typed in general.

For example, though I think createSlice() of redux-toolkit is a relly cool API, it returns a reducer which is typed as it accepts any action.

Another example is typescript-fsa whose action creators create actions whose type property is typed as string and not something like todo/FETCH_TODOS, resulting in implementing reducers whose interfaces are not strictly typed.

I think these problems can be solved if key augmentation during type mapping becomes available, so I'm waiting for it.

ts-react-redux-hooks's People

Contributors

heavenshell avatar kimamula avatar renovate-bot avatar renovate[bot] avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.