不保存React / Redux存储状态 [英] React/Redux store state is not saved
问题描述
我使用thunk中间件并将初始状态传递给React,但问题是当我访问其他链接时没有保存React状态。
成功登录后,它应该呈现仪表板。 >
当用户尝试转到 / login $时,必须重定向到仪表板(这是根路径,
/
) c $ c>页面。
I use thunk middleware and pass initial state to React, but the problem is that React state is not saved when I visit other links.
After successfully logged in, it's supposed to render dashboard.
User must be redirected to dashboard(which is the root path, /
) when he tries to go to /login
page.
我是否也应该使用redux-router?
Should i use redux-router too?
我省略了一些代码,但它几乎如下所示。
I omitted some of code, but it almost looks like below.
init.js
我将商店传递给提供商
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
const store = configureStore();
function requireAuth(nextState, replace) {
const isLoggedIn = store.getState().auth.isLoggedIn;
if (!isLoggedIn) {
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
});
}
}
<Provider store={store}>
<Router history={browserHistory}>
<Route path='/' component={App} store={store}>
<IndexRoute
components={{
main: MainServices,
aside: Aside
}}
onEnter={requireAuth}
/>
<Route
path="login"
components={{
login: Login
}}
/>
...
</Router>
</Provider>
configureStore.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index';
import initialState from './initialState';
const store = applyMiddleware(thunk)(createStore);
export default function () {
return store(rootReducer, initialState);
}
initialState.js
var initialState = {
auth: {
isLoggedIn: false,
isLoggingIn: false,
response: null,
},
};
export default initialState;
App.jsx
初始应用程序的状态通过到React的道具
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import Dashboard from './Dashboard';
import Login from './Login';
import { browserHistory } from 'react-router';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='appWrapper height'>
{
this.props.auth.isLoggedIn ?
<Dashboard {...this.props} /> : <Login {...this.props} />
}
</div>
);
}
}
let mapStateToProps = function(appState) {
return {
auth: appState.auth,
};
};
let mapDispatchToProps = function(dispatch) {
return {
logoutRequest: function() {
console.log("logoutRequest dispatched!");
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Login.jsx
export default class Login extends React.Component {
constructor(props) {
super(props);
console.log(`componentWillMount in login`);
if (this.props.auth.isLoggedIn) {
console.log(`you already logged in..!`);
browserHistory.push('/');
}
}
render() {
return (
<div className="login-outer">
<Grid className="login-inner">
<Row>
<Col xs={12}>
<LoginHeader />
<LoginContainer />
</Col>
</Row>
</Grid>
</div>
);
}
}
LoginContainer.jsx
export default class LoginContainer extends React.Component {
render() {
return (
<div className="login-container">
<div className="outer">
<div className="inner">
<LoginTitle />
<div className="login-box">
<h2>Sign in</h2>
<LoginInput />
</div>
</div>
</div>
</div>
);
}
}
LoginInput.jsx
import React from 'react';
import { connect } from 'react-redux';
import { Input, ButtonToolbar, Button } from 'react-bootstrap';
import { spring } from 'react-motion';
import Transition from 'react-motion-ui-pack';
import Loader from 'react-loader';
import * as actions from '../../actions/loginActions';
class LoginInput extends React.Component {
constructor(props) {
super(props);
this.state = {
idText: '',
passText: '',
idShow: false,
passShow: false,
loaded: true
};
this.handleIdChange = this.handleIdChange.bind(this);
this.handlePassChange = this.handlePassChange.bind(this);
this.loginRequest = this.loginRequest.bind(this);
}
handleIdChange(e) {
this.setState({
idText: e.target.value
});
if (e.target.value != '') {
this.setState({
idShow: true
});
} else {
this.setState({
idShow: false
});
}
}
handlePassChange(e) {
this.setState({
passText: e.target.value
});
if (e.target.value != '') {
this.setState({
passShow: true
});
} else {
this.setState({
passShow: false
});
}
}
loginRequest(e) {
this.setState({loaded: false});
if (!this.state.idText || !this.state.passText) {
this.setState({loaded: true});
}
if (this.state.idText && this.state.passText) {
this.setState({
loaded: false,
idText: this.state.idText,
passText: this.state.passText,
});
this.props.login(this.state.idText, this.state.passText);
}
e.preventDefault();
}
render() {
return (
<form className="loginForm">
<div className="form-group input-login id">
<input
type="text"
className="form-control"
ref="idText"
placeholder="ID"
value={this.state.idText}
onChange={this.handleIdChange}
/>
<Transition
component={false}
enter={{
opacity: 1
}}
leave={{
opacity: 0
}}
>
{
this.state.idShow &&
<label
htmlFor=""
className="control-label"
>
ID
</label>
}
</Transition>
</div>
<div className="form-group input-login password">
<input
type="password"
className="form-control"
ref="passText"
placeholder="Password"
value={this.state.passText}
onChange={this.handlePassChange}
/>
<Transition
component={false}
enter={{
opacity: 1
}}
leave={{
opacity: 0
}}
>
{
this.state.passShow &&
<label
htmlFor=""
className="control-label"
>
Password
</label>
}
</Transition>
</div>
<Input
type="checkbox"
groupClassName="checkbox-login"
label="Keep me signed in"
/>
<ButtonToolbar>
<Button
href="#"
onClick={this.loginRequest}
>
<div
className="sign-arrow"
hidden={!this.state.loaded}
>
<h6>
ENTER
</h6>
<img src="images/ic-right-arrow-2.svg" alt="" />
</div>
<Loader
className="spinner"
loaded={this.state.loaded}
lines={10}
length={3}
width={2}
radius={4}
corners={1}
rotate={0}
direction={1}
color="#fff"
speed={1.5}
trail={60}
shadow={false}
hwaccel={false}
scale={1}
/>
</Button>
</ButtonToolbar>
</form>
);
}
}
let mapStateToProps = function(appState) {
return {
auth: appState.auth,
};
};
let mapDispatchToProps = function(dispatch) {
return {
login: function(id, pwd) {
dispatch(actions.login(id, pwd));
}
}
};
export default connect(mapStateToProps,mapDispatchToProps)(LoginInput);
loginActions.js
export function loginFailure(error) {
return { error, type: ActionTypes.LOGIN_FAILURE };
}
export function loginSuccess(response) {
return dispatch => {
dispatch({ response, type: ActionTypes.LOGIN_SUCCESS });
browserHistory.push('/');
};
}
export function loginRequest(id, pwd) {
return {
type: ActionTypes.LOGIN_REQUEST,
command: 'login',
lang: 'en',
str: encodeCredentials(id, pwd),
ip: '',
device_id: '',
install_ver: '',
};
}
export function login(id, pwd) {
const credentials = loginRequest(id, pwd);
return dispatch => {
fetchJSON(`${API.ROOT_PATH}${API.END_POINT.LOGIN}`, {
method: 'post',
body: credentials,
}).then(data => {
dispatch(loginSuccess(data));
}).catch(error => {
console.log(`request failed ${error}`);
});
};
}
reducers / index.js
import authReducer from './authReducer';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
auth: authReducer,
});
export default rootReducer;
authReducer.js
import initialState from '../store/initialState';
import * as ActionTypes from '../actionTypes/authActionTypes';
const authReducer = function authReducer(state = initialState.auth, action) {
switch (action.type) {
case ActionTypes.LOGIN_REQUEST:
return Object.assign({}, state, {
isLoggingIn: true,
isLoggedIn: false,
});
case ActionTypes.LOGOUT:
return Object.assign({}, state, {
isLoggedIn: false,
isLoggingIn: false,
});
case ActionTypes.LOGIN_FAILURE:
return Object.assign({}, state, {
error: action.error,
isLoggingIn: false,
isLoggedIn: false,
});
case ActionTypes.LOGIN_SUCCESS:
return Object.assign({}, state, {
isLoggedIn: true,
isLoggingIn: false,
response: action.response,
});
default:
return state;
}
};
export default authReducer;
推荐答案
您的商店无法如何保存两个不同的http请求。唯一的方法是不重新加载页面本身,但是当用户通过使用历史API(在所有现代浏览器中是本机对象)进行操作来点击链接时,您可以模拟用户该页面被重新加载。但最好的方法是采用 react-router ,这将在您的反应应用程序中处理您需要的一切,如果您想在redux商店中保留路由器的状态,可以使用 redux-simple-router 。
There is no way how your store can be saved between two different http requests. The only approach for that is not reloading page itself, but you can emulate for user that page was reloaded when user clicks the link by manipulation with history API which is native object in all modern browsers. BUT best approach is to take react-router which will take care about everything you need in your react App, and if you want to keep state of the router in your redux store you can use redux-simple-router.
这篇关于不保存React / Redux存储状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!