我在一个新的带有redux的create-react-app react项目中使用redux-saga,由于某种原因,似乎redux-saga并未采取已调度的操作。 reducer中的控制台日志语句显示操作确实到达了reducer。奇怪的是,我已经将该项目基于我成功使用过redux-saga(但不是create-react-app)的其他项目。我想知道这是一个版本问题还是缺少一些支持包。以下是完整的代码段。
从我的package.json文件中:
"dependencies": {
"axios": "^0.19.0",
"connect-history-api-fallback": "^1.6.0",
"connected-react-router": "^6.5.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-google-login": "^5.0.5",
"react-redux": "^7.1.1",
"react-router-dom": "^5.0.1",
"react-scripts": "3.1.1",
"redux": "^4.0.4",
"redux-actions": "^2.6.5",
"redux-immutable-state-invariant": "^2.1.0",
"redux-persist": "^5.10.0",
"redux-saga": "^1.0.5",
"shortid": "^2.2.14",
"styled-components": "^4.3.2",
"styled-modern-normalize": "^0.2.0"
},
"devDependencies": {
"react-hot-loader": "^4.12.11",
"history": "^4.9.0"
},
最外面的index.js文件(我的应用程序的进入点):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './components/App';
import store from './store/config';
const render = (Component) => {
ReactDOM.render(
<Provider store={store}>
<Component />
</Provider>,
document.querySelector('#root')
);
};
render(App);
app.js文件基本上是一个容器组件,具有来自connected-react-router的已连接路由器,该路由器具有应用程序标头,然后是具有应用程序路由的交换机。我没有显示它,因为它实际上是一些嵌套的组件,可能会造成混淆。
我这样创建我的商店:
import {
applyMiddleware,
compose,
createStore,
} from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../root/rootReducer';
import sagas from '../root/rootSaga';
const sagaMiddleware = createSagaMiddleware();
const initialState = undefined;
const store = createStore(
rootReducer(history),
initialState,
applyMiddleware(sagaMiddleware),
);
sagaMiddleware.run(sagas);
export default store;
接下来是根减速器:
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import authReducer from '../auth/authReducer';
import { stateKeys } from '../../types';
export default history => combineReducers({
[stateKeys.ROUTER]: connectRouter(history),
[stateKeys.AUTH]: authReducer,
});
和根传奇:
import {
watchRegister,
watchSignin,
watchSignout,
} from '../auth/authSaga';
const root = function* rootSaga() {
yield [
watchRegister(),
watchSignin(),
watchSignout(),
];
};
export default root;
我的身份验证佐贺:
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects';
import api from '../../services/api';
import * as actions from '../root/rootActions';
function* signInSaga({ payload }) {
try {
console.log('saga hit...');
// console.log('email: ', email);
// console.log('password: ', password);
// yield put(actions.signinRequested());
// const response = yield call(api.signin, { email, password });
// console.log('response: ', response);
// yield put(actions.signinSucceeded(response));
} catch (error) {
console.log('saga failed...');
yield put(actions.signinFailed());
}
}
export function* watchSignin() {
yield takeEvery(actions.signin.toString(), signInSaga);
}
身份验证操作:
import { createAction } from 'redux-actions';
export const signin = createAction('auth/signin');
export const signinRequested = createAction('auth/signin_requested');
export const signinSucceeded = createAction('auth_signin_succeeded');
export const signinFailed = createAction('auth_signin_failed');
最终登录组件:
import React, { Component, Fragment} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link, Redirect } from 'react-router-dom';
import * as actions from '../../store/root/rootActions';
import * as selectors from '../../store/root/rootSelectors';
class Signin extends Component {
...
onSubmitClick = (event) => {
event.preventDefault();
this.setState({ loading: true });
const { email, password } = this.state;
const user = {
email,
password
};
// dispatching the action
this.props.signin(user);
};
renderSigninForm() {
const { email, password } = this.state;
return (
<form className="ui large form">
<div className="ui stacked segment">
<div className="field">
<div className="ui left icon input">
<i className="user icon"></i>
<input onChange={this.handleChange("email")} type="email" placeholder="john.smith@gmail.com" value={email} />
</div>
</div>
<div className="field">
<div className="ui left icon input">
<i className="lock icon"></i>
<input onChange={this.handleChange("password")} type="password" placeholder="Password" value={password} />
</div>
</div>
<div onClick={this.onSubmitClick} className="ui fluid large primary submit button">Log in</div>
</div>
</form>
);
}
render() {
if (this.state.redirectToReferer) {
return <Redirect to="/" />;
}
return (
<div className="ui middle aligned center aligned grid">
<div className="column">
<h2 className="content">Signin</h2>
{this.renderSigninForm()}
</div>
</div>
);
}
}
const mapStateToProps = state => ({
auth: selectors.getAuth(state),
});
const mapDispatchToProps = dispatch => ({
signin: user => dispatch(actions.signin(user)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Signin);
我为这篇文章的史诗般的长度表示歉意,但是如果没有所有内容,就很难提供完整的代码段。欢迎任何建议:)预先感谢
答案 0 :(得分:1)
似乎您的 root saga 文件没有调用saga方法来启动sagas。如文档所述:您应该调用all()
方法来运行传奇设置。 (例如https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html)。
因此重构的rootSaga.js如下所示:
import { all } from 'redux-saga/effects'
import {
watchRegister,
watchSignin,
watchSignout,
} from '../auth/authSaga';
const root = function* rootSaga() {
yield all([
watchRegister(),
watchSignin(),
watchSignout(),
]);
};
export default root;