resa
A simple framework based on typescript, redux, redux-saga, redux-action.
Installation
npm install resa --save
yarn add resa
Features
- No redundant redux boilerplate code
- Full IntelliSense with vscode and typescript
- Typed redux store
- Typed action creater and payload
- Better side effects control with redux-saga
- Action creater born to be promise
- Better error handling, support use promise.catch to capture error
- auto detect dependence of state, without mapStateToProps, more easy than connect of react-redux
- Easy learn, easy write, easy test
Motivation
Actually i like redux and redux-saga very much, but both them have many problems and they are not completely solved by existing packages like dva, mirror:
- Boilerplate code is everywhere when using redux, react-redux, redux-saga, redux-actions in the big project
- no IntelliSense
- no Type-safe
- terrible error handling in redux-saga
Examples
We hava integrated redux-devtool in online-vscode, you can click Open in New Window button and open chrome redux-devtool to see what action will be dispathed when you click button.
First sight
Define model
// AppModel.ts
import { Model, reducer, init, effect } from 'resa';
import { delay } from 'redux-saga';
interface AppState {
count: number;
}
@init<AppState>({
name: 'appModel',
namespace: 'namespace',
state: {
count: 0 // type check here
}
})
export default class AppModel extends Model<AppState> {
@effect() // define saga: async action handle
* addAsync(count: number) {
yield delay(2000);
this.add(count); // type check here
}
@reducer() // define redux reducer: sync action handle
add(count: number) {
return {
count: this.state.count + count, // type check here
};
}
}
Define component
// App.tsx
import * as React from 'react';
import AppModel from './AppModel';
import { subscribe, wapper } from 'resa';
interface AppProps {
appModel: AppModel; // annotation type, will inject by subscribe
}
class App extends React.Component<AppProps> {
render() {
return (
<div className="App">
<h1>{this.props.appModel.state.count}</h1>
{/* add and addAsync have been transformed to action creaters,
you just call them with arguments(type check payload)
*/}
<button onClick={() => this.props.appModel.add(1)}>+</button> {/* type check here */}
<button onClick={() => this.props.appModel.addAsync(2)}>async</button> {/* type check here */}
<button
onClick={() =>
wapper(this.props.appModel.addAsync(2)).then(() => {
alert('callback');
})
}>
promise
</button>
</div>
);
}
}
const NewApp = subscribe({ appModel: AppModel })(App);
export default NewApp;
wapper with Provider like react-redux
import createResa, { Provider } from 'resa';
import App from './App';
const app = createResa();
ReactDOM.render(
<Provider resa={app}>
<App />
</Provider>,
document.getElementById('root') as HTMLElement
);
So, do you like the simplicity ?
What is resa?
resa = a simple way to use redux and redux-saga
Docs
4.0 Break Change
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.