https://github.com/mizchi/use-react-redux-context
Alternative ReactRedux.connect by useContext for performance
https://github.com/mizchi/use-react-redux-context
react react-hooks react-redux redux
Last synced: 4 months ago
JSON representation
Alternative ReactRedux.connect by useContext for performance
- Host: GitHub
- URL: https://github.com/mizchi/use-react-redux-context
- Owner: mizchi
- Created: 2019-02-27T09:58:38.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-03-13T05:10:54.000Z (over 7 years ago)
- Last Synced: 2025-08-19T22:02:07.684Z (11 months ago)
- Topics: react, react-hooks, react-redux, redux
- Language: TypeScript
- Homepage:
- Size: 251 KB
- Stars: 43
- Watchers: 5
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# use-react-redux-context
Alternative `ReactRedux.connect()` by `useContext()` for performance.
```bash
# peer deps
$ yarn add react react-dom redux react-redux
$ yarn add use-react-redux-context
# or npm install --save use-react-redux-context
yarn add @types/react @types/redux @types/react-redux -D # for typescript
```
## Concept
- Pre-defined connected React.Context with mapState (no own props)
- Create bound actions by useCallback
- Emit render by shallow equal comparation
- TypeScript friendly
## Why not `useContext(ReactReduxContext)` of `react-redux@6`
Just `React.useContext(ReactReduxContext)` emits rendering by all state update. Pre-defined contexts and reducers are good for performance.
And I don't know good `ownProps` usages on `ReactRedux.connect`.
## How to use
Minimum conceptual code
```tsx
import { Provider as ContextProvider, Scope } from "use-react-redux-context";
import { Provider as ReactReduxProvider } from "react-redux";
const scope = new Scope();
const RootStateContext = scope.createContext(s => s);
const All = () => {
const all = useContext(RootStateContext);
return
{JSON.stringify(all)};
};
const store = createStore(reducer); // create your reducer
const el = (
);
```
Working code
```tsx
import React, { useContext, useCallback, useEffect } from "react";
import ReactDOM from "react-dom";
import { createStore, combineReducers, Reducer } from "redux";
import { Provider as ReactReduxProvider } from "react-redux";
import { Provider as ContextProvider, Scope } from "use-react-redux-context";
// Write your own reducer
type Foo = {
value: number;
};
type RootState = {
foo: Foo;
};
type IncrementAction = { type: "increment" };
type Action = IncrementAction;
function foo(state: Foo = { value: 0 }, action: Action): Foo {
switch (action.type) {
case "increment": {
return { value: state.value + 1 };
}
default: {
return state;
}
}
}
function increment(): IncrementAction {
return { type: "increment" };
}
// Build connected React.Context
const scope = new Scope(); // scope expand all contexts
const FooContext = scope.createContext((state, dispatch) => {
// this useCallback is under NewContext rendering hook context
const inc = useCallback(() => dispatch(increment()), []);
// emit render by shallow equal comparation
return { ...state.foo, inc };
});
function Counter() {
// This is React.useContext, not library function
const foo = useContext(FooContext);
return (
value: {foo.value}
+1
);
}
const rootReducer: Reducer = combineReducers({ foo });
const store = createStore(rootReducer);
function App() {
return (
// Provider expand all scope's context
);
}
// @ts-ignore
ReactDOM.render(, document.querySelector(".root") as HTMLDivElement);
```
## API
### `useDispatch`
Get `store.dispatch` Function
```tsx
import { useDispatch } from "use-react-redux-context";
function X() {
const dispatch = useDispatch();
return (
disptach({ type: "my-action" })}>my action
);
}
```
### `useBindAction`, `useBindActions`
Create function by action and actionMap (with `useCallback` and its `memoizedKeys`)
```tsx
import { useBindAction, useBindActions } from "use-react-redux-context";
const A = scope.createContext(state => {
const inc = useBindAction(increment);
// with memoized keys
// const inc = useBindAction(() => ({type: 'increment', payload: state.value}), [state.value]);
return { ...state.a, inc };
});
const B = scope.createContext(_state => {
const actions = useBindActions({ increment, decrement });
// alternative: with memoized keys map
// const actions = useBindActions({ increment, decrement }, { increment: [state.value] });
// recommend spreading for shallow equal
return { ...actions };
});
```
## How to dev
- `yarn build`: Build `index.js`
- `yarn test`: Run jest
- `yarn demo`: Start application server on `http://localhost:1234`
- `yarn demo:deploy`: Deploy to netlify (need netlify account)
## LICENSE
MIT