redux-saga-resources
See also redux-saga-resources-example
Module under development
Why
Things you won't have to think about:
- Retrying.
- Editing state.
- Race conditions between actions.
- Lazy loading.
- Maintaining consistent state during errors like timeouts.
- IDs of new items and syncing them when created.
- Handling HTTP/REST return codes.
Examples
Usage
Install
npm install --save redux-saga-resources redux-saga-rest
Configuration (TypeScript)
import { API, defaultMiddleware } from 'redux-saga-rest';
import { createResource, createEditor, httpMiddleware } from 'redux-saga-resources';
const api = new API('/api')
.use(defaultMiddleware());
export const resource = createResource('post', {}, httpMiddleware('/posts', api));
export const editor = createEditor('post', {}, resource);
Configuration (ES6)
import { API, defaultMiddleware } from 'redux-saga-rest';
import { createResource, createEditor, httpMiddleware } from 'redux-saga-resources/es6';
const api = new API('/api')
.use(defaultMiddleware());
export const resource = createResource('post', {}, httpMiddleware('/posts', api));
export const editor = createEditor('post', {}, resource);
Implementation
import { createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
const saga = createSagaMiddleware();
const store = createStore(
combineReducers({
postResource: resource.reducer,
postEditor: editor.reducer
}),
null,
applyMiddleware(
saga
)
);
saga.run(resource.saga);
Examples
store.dispatch(resource.creators.doList());
store.dispatch(resource.creators.doCreate(resource.create({ title: 'New Post' })));
store.dispatch(editor.creators.doCreate({ title: 'New Post' }));
Configuration
Editor
createImmediately
When editor is requested to create a new item the request is passed to the resource. When createImmediately
is false
the item will only be created during the first update.
export const editor = createEditor('post', { createImmediately: false }, resource);
React
List of items
@connect(
(state) => ({
items: resource.selectors.items(state)
}),
(dispatch) => ({
create: () => dispatch(editor.creators.doCreate({ title: 'New Post' })),
edit: (item) => dispatch(editor.creators.doEdit(item))
})
)
class App extends Component {
render() {
return (
<div>
<button type="button" onClick={() => this.props.create()}>New Post</button>
{this.props.items.map(post => (
<div class="item">
{post.title}
<button type="button" onClick={() => this.props.edit(post)}>edit</button>
</div>
))}
</div>
)
}
}
Edit single item
@connect(
(state) => ({
item: editor.selectors.item(state),
unmodified: resource.fields.isUnmodified(editor.selectors.item(state)),
neverCommited: resource.fields.neverCommited(editor.selectors.item(state))
}),
(dispatch) => ({
create: () => dispatch(editor.creators.doCreate({ title: 'New Post' })),
edit: (item) => dispatch(editor.creators.doEdit(item)),
reload: (item) => dispatch(editor.creators.doRead(item)),
save: (item) => dispatch(editor.creators.doUpdate(item)),
remove: (item) => dispatch(editor.creators.doDelete(item))
})
)
class BlogPost extends Component {
render() {
return (
<form>
<input placeholder="Title" value={this.props.item.title} onChange={(e) => this.props.edit({ ...this.props.item, title: e.target.value })} />
<br/>
<button type="button" onClick={() => this.props.create()}>New</button>
<button type="button" onClick={() => this.props.reload()} disabled={this.props.neverCommited}>Reload</button>
<button type="button" onClick={() => this.props.remove()} disabled={this.props.neverCommited}>Delete</button>
<button type="button" onClick={() => this.props.save()} disabled={this.props.unmodified}>Save</button>
</form>
)
}
}