Introduction

Installation
Using npm:
npm install redux-sands
Using yarn:
yarn add redux-sands
Basics
redux-sands
gives you a single class as default export, from now on called ReduxWrapper
. Here's a simple example that demonstrates how you could use it:
import ReduxWrapper from "redux-sands";
import component from "./component";
// Instantiate the wrapper.
const wrapper = new ReduxWrapper({ called: "example" });
// Simply add the initial state, the component for render + a reducer.
wrapper
.add({ initState: { count: 0 } })
.add({ component })
.add({ update: (state, action) => ({ ...state, ...action }) });
// Expose the redux-wrapper as any other redux-component.
export default wrapper.connection;
export const reducer = wrapper.reducer;
And now let's call it:
class Comp extends PureComponent {
render() {
// When using 'ReduxWrapper', only an object as param is allowed.
// Provide your values then via that object.
return (
<div onClick={() => this.props.update({ count: this.props.count + 1 })}>
Increment
</div>
);
}
}
As far as basic use cases go, that's it! No more hassle with manually creating actions, mappings and endless switches. Action-types get inferred automatically, as well as the linking to the reducer. You can focus on the actual app logic without having to deal with refactoring etc.
redux-sands
only works when calling the reducer with an object as param. You have to provide your state-changing values there.
Importing
Furthermore, ReduxWrapper
provides additional skills to simplify redux-usage:
...
wrapper
.add({ initState: { count: 0 } })
.add({ component })
.add({ update: (state, action) => ({ ...state, ...action }) })
.import({ reducer: { otherReduxComp: ["reset", { origin: "delete", as: "otherDelete" }] } })
.import({ state: { otherReduxComp: ["schemas"] } });
// Expose the redux-wrapper as any other redux-component.
// Important: 'saga' has to be exported when using 'import(...)' and integrated into the store-middleware.
export default wrapper.connection;
export const reducer = wrapper.reducer;
export const saga = wrapper.saga;
You're able to import reducers as well as state-props from other ReduxWrapper
s in a dead-simple fashion. As demonstrated above, you can either import them 'as-is' or apply renaming.
When importing reducers, you have to hook up the saga-export to the saga-middleware in your app. Else the action won't get fired.
If you don't have it installed yet, here's the project.
Behind the scenes
redux-sands
internally uses proxies to import reducers from other comps. This is necessary b/c we can't guarantee that the component we're importing from has already been instantiated. Therefore, when an import is declared, the wrapper instance creates a unique proxy for that action. Upon calling, this proxy gets fired, which itself fires saga to dispatch the actual action.
This race-condition doesn't occur when statically importing the reducers to your store. But since we're working here at runtime, redux may not find the other's reducer during its init, since it hasn't been created yet.
Saga is necessary, b/c dispatching actions in other reducers is a non-pattern. Hence we're dispatching the requested action as a controlled side effect via saga.
Saga-integration
Last but not least, as hinted above, redux-saga
is also supported. Here's how:
...
wrapper
.add({ initState: { data: {} } })
.add({ component })
.add({
refetch: {
fn: (state, { data = {} }) => {
return { ...state, data };
},
withSaga: {
takeEvery: function*(action) {
const { url, result, put } = action;
try {
const data = yield fetch(url);
yield put({ ...result, data });
} catch (e) {
yield put({ ...result, error: e });
}
}
}
}
})
// Expose the redux-wrapper as any other redux-component.
export default wrapper.connection;
export const reducer = wrapper.reducer;
export const saga = wrapper.saga;
Here you can see a dummy-implementation that leverages the saga-integration. You provide both the standard reducer-function and a saga-function. The specific saga-fn gets derived by its key with the value representing the actual generator-method used by saga. After the async calls are done, you place your params in the 'put' method, which is provided in the action (including call
from saga). The params then get passed to the reducer, where stuff gets done as usual.
That's it for an overview. For detailed info, take a look at the API-specs following.
Last updated