
react-rewired
Wire your react app as easy as possible...
- A fast and easy alternative for
react-redux
- Feels more like react (using internal react state as base model)
TypeScript
support included
flow
support included
- very small package size (v3.0.2 -> 836 B gzipped)
- high performance (performance play ground in comparison to
react-redux@7.1.1
is available here)
Introduction
react-rewired
intends to reduce the overhead and complexity when internal
react component state is not enough, because you want to store everywhere
accessible data which can safely be accessed by your react components
and triggers automatically updates, when the data changes.
This should be familiar to any react developer. And the more popular solution
for this purpose is the usage of react-redux
. But react-redux
comes not
only with nice dev tools, good documentation, large user base and a consistent
philosophy for its usage and idea. In my opinion, I am still looking to often
into the dev tools to find out what seems to be broken and my application grows
very fast too large with all the overhead, that comes with actions and reducers.
Also it is always quite an act to implement flow
on top of react-redux
.
How to - an example
First of all you need to initialize your Store
with some defaults.
import { Wired } from 'react-rewired';
const Store = Wired.store({
num: 12,
data: { keys: [] },
foo: null
})
You will also have to define the types for your State
because the
breaking change since flow
reached version 0.85
requires to define any types in value position.
Now let's e.g. define the array on data.keys
to contain only strings.
type DataState = { keys: string[] };
type State = {
num: number,
data: DataState,
foo: string | null
};
const data: DataState = { keys: [] };
const Store = Wired.store<State>({
num: 12,
data,
foo: null
})
- HINT: Types in value position are still very new, but every flow-parser
is able to handle those. If you run in troubles with those, you should
maybe consider to update your dev dependencies.
The next step is the wrapping of your react tree with the context provider
to be able to access the data within any component of the subtree.
const root = document.getElementById('root');
root &&
ReactDOM.render(
<Store.root>
<App />
</Store.root>,
root
);
To access the data within your component you want to wrap it into the
corresponding consumer. (HINT: You should not define react components
inline but give it a name, because the react dev tools uses that name as
default display name. E.g. in the following snippet "MyComponent" will
be displayed inside the react dev tools)
type MyComponentStoreProps = {| key?: string, odd: boolean |};
type MyComponentOwnProps = {||};
type MyComponentProps = {| ...MyComponentOwnProps, ...MyComponentStoreProps |};
const MyComponent = ({ key, odd }: MyComponentProps) => <JSX />
const MyWiredComponent = Store.wire<MyComponentStoreProps, MyComponentOwnProps>(
MyComponent,
state => ({
key: state.data.keys[0],
odd: state.num % 2 === 1
})
);
- HINT: I want to stress out that your application will benefit a lot if
you follow the above pattern everywhere. Also I want to strongly encourage
you, to use always (if possible) exact prop types, to ensure that no arbitrary
props will be provided where not expected.
The last thing you have to know are state updates. There are two different ways you
can perform those updates. Just like setState
on internal react state.
Store.set({ num: 13, foo: 'bar' });
Store.set(state => ({ num: 3 * state.num }));
If you want to access the data directly e.g. outside any component, you can
do the following:
const state = Store.get();
-
ATTENTION: Modifications to the returned state can effect your application in
an unexpected way. Even if you know what you're doing, I do not recommend it.
-
To make testing easy even with the context API, you should insert a little snippet into your setupTests.js
(see jest
option "setupFilesAfterEnv")
Store.set = (Component, mapStateToProps) => {
const result = props => <Component {...mapStateToProps(Store.get())} {...props} />;
result.displayName = `Wired(${Component.displayName || Component.name || ''})`;
return result;
}