98k 中文文档教程
98k
一个基于 react、redux、redux-saga 和 react-router-dom 的轻量级包装器,旨在将您从创建 action creator、reducer、sagas 等(受 dva 启发)的繁琐步骤中解放出来。
Install
$ npm install --save 98k
Quick start
index.js
import Kar98k from '98k';
import counter from './counter';
const app = Kar98k();
//app.middleware(middlewares); //apply redux middlewares here
app.module(counter);
app.start('#app');
counter.js
import React from 'react';
import { connect } from '98k';
const Counter = connect(state => state.counter)(({ dispatch, count }) => (
<div>
<div>count: {count}</div>
<button onClick={() => dispatch({
type : 'counter/add',
payload : 1,
})}>add</button>
</div>
));
export default {
namespace : 'counter',
state : {
count: 0,
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
actionType 是 reducers
的关键属性,前缀为 namespace
。
Options
const app = Kar98k({
router: 'hash', // 'hash','browser'
basename: '/', // the baseUrl used in react-router
});
Asynchronous action
const Counter = connect(state => state.counter)(({ dispatch, count }) => (
<div>
<div>count: {count}</div>
<button onClick={() => dispatch({
type : 'counter/asyncAdd',
payload : 2,
})}>asyncAdd</button>
</div>
));
export default {
namespace : 'counter',
state : {
count: 0,
},
effects: {
*asyncAdd({ payload }, { put, call }, { delay }) {
yield call(delay, 1000);
yield put({ type: 'counter/add', payload });
},
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
Routing
const App = connect(state => state.example)(({ match: { params: { id } } }) => (
<div>routing example: {id}</div>
));
export default {
namespace : 'example',
routes : {
'/example/:id': { component: App },
},
};
Navigate routes programmatically
export default {
namespace: 'example',
effects: {
*redirectToRoutes({ payload }, { call }, { history }) {
const { data } = call(services.someApi, payload);
if(data) {
history.push('/some/routes');
} else {
history.push('/other/routes');
}
},
},
};
Error handling
export default {
namespace : 'counter',
state : {
count: 0,
},
effects: {
*asyncAdd({ payload }, { put, call }, { delay }) {
yield call(delay, 1000);
throw 'some error';
yield put({ type: 'counter/add', payload });
},
},
catch: function*(err, action, { put }) {
console.log(err);
console.log(action);
yield put({ type: 'counter/add', payload });
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
Plugin
您可以通过 app.use
添加插件。
index.js
import Kar98k from '98k';
import loading from './loading';
import counter from './counter';
const app = Kar98k();
app.use(loading())
.module(counter)
.start('#app');
插件只是一个获取两个参数的函数:injectReducer
和 injectEffect
。
injectReducer
用于添加额外的 reducer。
injectEffect
基本上用于添加包装 saga 函数的高阶函数。
export default (injectReducer, injectEffect) => {
const initialState = {};
injectReducer({
loading(state = initialState, { type, payload }) {
const { namespace } = payload || {};
switch(type) {
case '@@98k/show':
return {
...state,
[namespace]: true,
};
case '@@98k/hide':
return {
...state,
[namespace]: false,
};
default:
return state;
}
},
});
injectEffect((saga, module, type, { put, call }, { delay }) => {
const { namespace } = module;
return function*(action) {
yield put({ type: '@@98k/show', payload: { namespace, type } });
yield saga(action);
yield call(delay, 1000);
yield put({ type: '@@98k/hide', payload: { namespace, type } });
};
});
}
>loading.js injectEffect
的参数是:
saga
- 当前被触发的 saga 函数
module
- 模块此 saga 属于
type
的对象 - 当前操作
和 saga 助手的类型。
98k
a lightweight wrapper based on react, redux, redux-saga and react-router-dom, that aims to free you from tedious steps of creating action creators, reducers, sagas etc(inspired by dva).
Install
$ npm install --save 98k
Quick start
index.js
import Kar98k from '98k';
import counter from './counter';
const app = Kar98k();
//app.middleware(middlewares); //apply redux middlewares here
app.module(counter);
app.start('#app');
counter.js
import React from 'react';
import { connect } from '98k';
const Counter = connect(state => state.counter)(({ dispatch, count }) => (
<div>
<div>count: {count}</div>
<button onClick={() => dispatch({
type : 'counter/add',
payload : 1,
})}>add</button>
</div>
));
export default {
namespace : 'counter',
state : {
count: 0,
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
actionType is the key properties of reducers
prefixed by namespace
.
Options
const app = Kar98k({
router: 'hash', // 'hash','browser'
basename: '/', // the baseUrl used in react-router
});
Asynchronous action
const Counter = connect(state => state.counter)(({ dispatch, count }) => (
<div>
<div>count: {count}</div>
<button onClick={() => dispatch({
type : 'counter/asyncAdd',
payload : 2,
})}>asyncAdd</button>
</div>
));
export default {
namespace : 'counter',
state : {
count: 0,
},
effects: {
*asyncAdd({ payload }, { put, call }, { delay }) {
yield call(delay, 1000);
yield put({ type: 'counter/add', payload });
},
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
Routing
const App = connect(state => state.example)(({ match: { params: { id } } }) => (
<div>routing example: {id}</div>
));
export default {
namespace : 'example',
routes : {
'/example/:id': { component: App },
},
};
Navigate routes programmatically
export default {
namespace: 'example',
effects: {
*redirectToRoutes({ payload }, { call }, { history }) {
const { data } = call(services.someApi, payload);
if(data) {
history.push('/some/routes');
} else {
history.push('/other/routes');
}
},
},
};
Error handling
export default {
namespace : 'counter',
state : {
count: 0,
},
effects: {
*asyncAdd({ payload }, { put, call }, { delay }) {
yield call(delay, 1000);
throw 'some error';
yield put({ type: 'counter/add', payload });
},
},
catch: function*(err, action, { put }) {
console.log(err);
console.log(action);
yield put({ type: 'counter/add', payload });
},
reducers: {
add(state, { payload }) {
return { ...state, count: state.count + payload };
},
},
routes: {
'/': { component: Counter },
},
};
Plugin
you can add plugins via app.use
.
index.js
import Kar98k from '98k';
import loading from './loading';
import counter from './counter';
const app = Kar98k();
app.use(loading())
.module(counter)
.start('#app');
A plugin is just a function that gets two parameters: injectReducer
and injectEffect
.
injectReducer
is used to add extra reducers.
injectEffect
is basically used to add a higher-order function that wraps saga function.
loading.js
export default (injectReducer, injectEffect) => {
const initialState = {};
injectReducer({
loading(state = initialState, { type, payload }) {
const { namespace } = payload || {};
switch(type) {
case '@@98k/show':
return {
...state,
[namespace]: true,
};
case '@@98k/hide':
return {
...state,
[namespace]: false,
};
default:
return state;
}
},
});
injectEffect((saga, module, type, { put, call }, { delay }) => {
const { namespace } = module;
return function*(action) {
yield put({ type: '@@98k/show', payload: { namespace, type } });
yield saga(action);
yield call(delay, 1000);
yield put({ type: '@@98k/hide', payload: { namespace, type } });
};
});
}
parameters of injectEffect
are:
saga
- the current saga function that is being triggered
module
- the module object that this saga belongs to
type
- type of the current action
and saga helpers.