Appearance
跳转路径
本节目标:理解“跳转路径”的核心思路,并能把它用于实际开发或面试表达。 使用
6.1.1 src\index.js
src\index.js
import React from 'react';import dva, { connect } from './dva';+import { Router, Route,Link,routerRedux } from './dva/router';+import { ConnectedRouter } from 'connected-react-router';const app = dva();app.model({ namespace: 'counter', state: { number: 0 }, reducers: { add(state) { return { number: state.number + 1 }; } }, effects: { *asyncAdd(action, { call, put }) { yield call(delay, 1000); yield put({ type: 'counter/add' }); },+ *goto({ to }, { put }) {+ yield put(routerRedux.push(to));+ }}});function Counter(props) { return ( <div> <p>{props.number}</p> <button onClick={() => props.dispatch({ type: "counter/add" })}>+</button> <button onClick={() => props.dispatch({ type: "counter/asyncAdd" })}>异步
+</button>+ <button onClick={() => props.dispatch({ type: "counter/goto", to: '/' })}>跳转到
/</button></div> )}const ConnectedCounter = connect( (state) => state.counter)(Counter);const Home = () => <div>Home</div>app.router((api) => (+ <ConnectedRouter history={api.history}><> <Link to="/">Home</Link> <Link to="/counter">Counter</Link> <Route path="/" exact={true} component={Home} /> <Route path="/counter" component={ConnectedCounter} /> </> </ConnectedRouter >));app.start('#root');
function delay(ms) { return new Promise((resolve) => { setTimeout(function () { resolve(); }, ms); });}
6.2实现
6.2.1 dva\index.js
src\dva\index.js
import React from 'react';import ReactDOM from 'react-dom';import { createStore, combineReducers, applyMiddleware } from 'redux';import createSagaMiddleware from 'redux-saga';import * as sagaEffects from 'redux-saga/effects';import { NAMESPACE_SEP } from './constants';import { connect, Provider } from 'react-redux';import prefixNamespace from './prefixNamespace';import { createHashHistory } from 'history';+import { routerMiddleware, connectRouter, ConnectedRouter } from "connected-react-router";let history = createHashHistory();export { connect };
function dva() { const app = { _models: [], model, router, _router: null, start }+ const initialReducers = { router: connectRouter(history) };function model(model) { const prefixedModel = prefixNamespace(model); app._models.push(prefixedModel); return prefixedModel; } function router(router) { app._router = router; }
function start(root) { for (const model of app._models) { initialReducers[model.namespace] = getReducer(model); } let rootReducer = createReducer(); const sagas = getSagas(app); const sagaMiddleware = createSagaMiddleware();+ let store = createStore(rootReducer, applyMiddleware(routerMiddleware(history), sagaMiddleware));sagas.forEach(saga => sagaMiddleware.run(saga)); ReactDOM.render(<Provider store={store}>{app._router({ history })}</Provider>, document.querySelector(root)) function createReducer() { return combineReducers(initialReducers); } } function getSagas(app) { let sagas = []; for (const model of app._models) { sagas.push(getSaga(model.effects, model)); } return sagas; } return app;}function getSaga(effects, model) { return function* () { for (const key in effects) { const watcher = getWatcher(key, model.effects[key], model); yield sagaEffects.fork(watcher); } };}function getWatcher(key, effect, model) { return function* () { yield sagaEffects.takeEvery(key, function* sagaWithCatch(...args) { yield effect(...args, { ...sagaEffects, put: action => sagaEffects.put({ ...action, type: prefixType(action.type, model) }) }); }); };}function prefixType(type, model) { if (type.indexOf('/') === -1) {return `${model.namespace}${NAMESPACE_SEP}${type}`; } return type;}function getReducer(model) { let { reducers, state: defaultState } = model; let reducer = (state = defaultState, action) => { let reducer = reducers[action.type]; if (reducer) { return reducer(state, action); } return state; } return reducer;}
export default dva;
6.2.2 src\dva\router.js
src\dva\router.js
import * as routerRedux from 'connected-react-router';export * from 'react-router-dom';export { routerRedux}> 来自
<http://www.zhufengpeixun.com/strong/html/106.8.dva.html>