react-redux-partial
v0.2.0
Published
Library to improve performance when you have many components connected to different part of the store. Also it helps to create connected components which are independent of shape of root redux store.
Maintainers
Readme
react-redux-partial
This library is a wrapper of the original react-redux library and use it inside. react-redux-partial has beed created for 2 reasons:
- improve performance of an application when large amount of connected components are used
- write connected react-components which are independent of a shape of redux store
Performance improvement
Consider, you have a redux store of this interface:
interface PageState {
loginForm: LoginFormType;
items: SomeItemsType;
}And you have a few dozens of components connected to the items field of the store. Then each action which changes loginForm will cause call of all selectors of components connected to theitems. It can be slowly.
Using react-redux-partial you can easy connect components to the items field such way the corresponding selectors are called when only the items fields is changed.
Independent connected components
Using react-redux-partial you can create a connected to a store component which can work with a state of some interface. For example:
interface LoginFormType {
login: string;
password: string;
}And then you can reuse this component on any page where a redux state has the login form data in any field.
API
createConnects
createConnects function returns a set of methods to connect component to a part of a redux store.
import { createConnects } from 'react-redux-partial';
type LoginFormType = {
login: string;
password: string;
};
const { connect } = createConnects<LofinFormType>();createConnects returns an object with fields:
- context
- useDispatch
- useSelector
- useStore
- connect
- Provider
- withProvider
context
createConnects returns a new context object. It can be use directly or as a parameter of original Provider and connect from react-redux. All other methods returned by createConnects work only with this context.
useDispatch, useSelector, useStore, connect
These functions work as original useDispatch, useSelector, useStore, connect functions from react-redux but only with a context returned by the same createConnects call.
Provider
The Provider component adds a store to react context. To get the store from context you can use the context returned by createConnects or any of methods useDispatch, useSelector, useStore, connect.
Pass a store
You can use Provider as you usually use the react-redux provider.
import { render } from 'react';
import { createConnects } from 'react-redux-partial';
import { createStore } from 'redux';
import SomeComponent from './SomeComponent';
type LoginFormType = {
login: string;
password: string;
};
const store = createStore(/* arguments */);
const { Provider, connect } = createConnects<LofinFormType>();
const ConnectedComponent = connect(/* arguments */)(SomeComponent);
render(
<Provider store={store}>
<ConnectedComponent />
</Provider>,
element
);Pass a parent context
Also you can create some ConnectedComponent and use it with stores which contain a state of different types.
Component.tsx
export type LoginFormType = {
login: string;
password: string;
};
const { Provider, connect } = createConnects<LofinFormType>();
export const ConnectedComponent = connect(/* arguments */)(SomeComponent);
export { Provider };You can pass to the Provider a parent context and a field where is a state of type LoginFormType.
import { render } from 'react';
import { createConnects } from 'react-redux-partial';
import { createStore } from 'redux';
import ConnectedComponent, {
LoginFormType,
Provider as ConnectedComponentProvider,
} from './Component';
type PageStateLoginFormType = {
loginForm: LoginFormType;
};
const store = createStore(/* arguments */);
const { Provider, context } = createConnects<PageStateLoginFormType>();
render(
<Provider store={store}>
<ConnectedComponentProvider context={context} fields="loginForm">
<ConnectedComponent />
</ConnectedComponentProvider>
</Provider>,
element
);Selectors which are passed to connect will be invoked only if the loginForm field is changed. This can improve a page performance.
Also you can pass a select props if you want to transform parent state to chils state. For example:
import ConnectedComponent, {
LoginFormType,
Provider as ConnectedComponentProvider,
} from './Component';
type PageStateLoginFormType = {
loginForm: {
email: string;
pass: string;
};
/** some other fields */
};
function selector(state: { email: string; pass: string }): LoginFormType {
return {
login: state.email,
password: state.pass,
};
}
render(
<Provider store={store}>
<ConnectedComponentProvider
context={context}
fields="loginForm"
select={selector}
>
<ConnectedComponent />
</ConnectedComponentProvider>
</Provider>,
element
);Or you can pass an object instead of a string to fields prop.
import ConnectedComponent, {
LoginFormType,
Provider as ConnectedComponentProvider,
} from './Component';
type PageStateLoginFormType = {
user: {
email: string;
phone: string;
};
pass: string;
orders: any[];
};
function selector(state: {
user: {
email: string;
};
pass: string;
}): LoginFormType {
return {
login: state.user.email,
password: state.pass,
};
}
render(
<Provider store={store}>
<ConnectedComponentProvider
context={context}
fields={{
user: { email: true },
pass: true,
}}
select={selector}
>
<ConnectedComponent />
</ConnectedComponentProvider>
</Provider>,
element
);For each prop you want to pass to a child provider you should specify true. Also you can use select prop to transform parent state.
Use custom partial provider instead of original
I some cases you may have to use a original react-redux provider in a page root. If you have some components which are connected with methods returned by createConnects, then you should use a Provider component from react-redux-partial instead of original. It has the same behavior but turns on performance optimization.
Override original react-redux context
If you want to use some component connected by original connect you can you use OverrideStoreProvider to connect it to a partial store. It can improve performance.
With partial root provider.
import { createConnects, OverrideStoreProvider } from 'react-redux-partial';
const { Provider, context } = createConnects();
const store = createStore();
<Provider store={store}>
...
<OverrideStoreProvider context={context} fields="someField">
<ConnectedComponent />
</OverrideStoreProvider>
...
</Provider>;With original root provider.
import { Provider } from 'react-redux';
import { OverrideStoreProvider } from 'react-redux-partial';
const store = createStore();
<Provider store={store}>
...
<OverrideStoreProvider fields="someField">
<ConnectedComponent />
</OverrideStoreProvider>
...
</Provider>;