我有以下情况:用户输入他的凭据并单击a 登录 按钮。 API调用在动作创建者中完成 redux-thunk
。 API调用成功后,将调度另一个包含服务器响应的操作。在(成功)登录后,我想将用户会话ID存储在cookie中(通过 react-cookie
)。
行动创造者
export function initiateLoginRequest(username, password) {
return function(dispatch) {
dispatch(loginRequestStarting())
return fetch('http://path.to/api/v1/login',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password
})
})
.then(checkStatus)
.then(parseJSON)
.then(function(data) {
dispatch(loginRequestSuccess(data))
})
.catch(function(error) {
dispatch(loginRequestError(error))
})
}
}
export function loginRequestSuccess(user) {
return {
type: ActionTypes.LOGIN_REQUEST_SUCCESS,
user
}
}
减速器
export default function user(state = initialState, action) {
switch (action.type) {
case ActionTypes.LOGIN_REQUEST_SUCCESS:
cookie.save('sessionId', action.user.sid, { path: '/' })
return merge({}, state, {
sessionId: action.user.sid,
id: action.user.id,
firstName: action.user.first_name,
lastName: action.user.last_name,
isAuthenticated: true
})
default:
return state
}
}
现在减速机负责 LOGIN_REQUEST_SUCCESS 保存cookie。我知道减速机必须是 一个纯粹的功能。
是否在减速器中保存了一个违反此原则的cookie?将cookie保存在动作创建者中会更好吗?
看一下 终极版 - 坚持。
您可以保留/保存您的减速器(或其中的一部分) LocalStorage
。
概念
- 启动登录。
- 从服务器接收cookie。
- 调度登录成功。
- Reducer将cookie存储在内存中。
- 持久中间件在LocalStorage中存储reducer状态。
例
安装
npm install --save-dev redux-persist
示例用法
创建一个包装持久性/补液逻辑的组件。
AppProvider.js
import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
class AppProvider extends Component {
static propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
constructor(props) {
super(props);
this.state = { rehydrated: false };
}
componentWillMount() {
const opts = {
whitelist: ['user'] // <-- Your auth/user reducer storing the cookie
};
persistStore(this.props.store, opts, () => {
this.setState({ rehydrated: true });
});
}
render() {
if (!this.state.rehydrated) {
return null;
}
return (
<Provider store={this.props.store}>
{this.props.children}
</Provider>
);
}
}
AppProvider.propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
export default AppProvider;
然后,在你的 index.js
或您在其中设置的文件 store
,将渲染的组件包装在新的组件中 AppProvider
。
index.js
...
import AppProvider from 'containers/AppProvider.jsx';
...
render((
<AppProvider store={store}>
...
</AppProvider>
), document.getElementById('App'));
这将序列化你的 user
减速机状态到 LocalStorage
每次更新商店/州时。您可以打开您的开发工具(Chrome)并查看 Resources
=> Local Storage
。
看一下 终极版 - 坚持。
您可以保留/保存您的减速器(或其中的一部分) LocalStorage
。
概念
- 启动登录。
- 从服务器接收cookie。
- 调度登录成功。
- Reducer将cookie存储在内存中。
- 持久中间件在LocalStorage中存储reducer状态。
例
安装
npm install --save-dev redux-persist
示例用法
创建一个包装持久性/补液逻辑的组件。
AppProvider.js
import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
class AppProvider extends Component {
static propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
constructor(props) {
super(props);
this.state = { rehydrated: false };
}
componentWillMount() {
const opts = {
whitelist: ['user'] // <-- Your auth/user reducer storing the cookie
};
persistStore(this.props.store, opts, () => {
this.setState({ rehydrated: true });
});
}
render() {
if (!this.state.rehydrated) {
return null;
}
return (
<Provider store={this.props.store}>
{this.props.children}
</Provider>
);
}
}
AppProvider.propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
}
export default AppProvider;
然后,在你的 index.js
或您在其中设置的文件 store
,将渲染的组件包装在新的组件中 AppProvider
。
index.js
...
import AppProvider from 'containers/AppProvider.jsx';
...
render((
<AppProvider store={store}>
...
</AppProvider>
), document.getElementById('App'));
这将序列化你的 user
减速机状态到 LocalStorage
每次更新商店/州时。您可以打开您的开发工具(Chrome)并查看 Resources
=> Local Storage
。
我可能让服务器端亲自设置cookie,并使其对JavaScript透明。但如果你真的想在客户端做这件事,我会在动作助手中做到这一点。像这样的东西:
// Using redux-thunk
function login(user, password) {
return dispatch => api.auth.login(user, password)
.then(result => setCookie())
.then(() => dispatch({type: 'USER_LOGGED_IN'}))
}
或类似的东西。
动作助手不需要纯粹,但减速器应该是。所以,如果我正在做副作用,我会把它们付诸行动助手。
我不确定这是否是“正确的”方式,但这就是我的团队如何在我们构建的Redux应用程序中保留已登录用户:
我们有一个非常默认的架构,一个准备好在一侧接收请求的API,以及一个在另一侧使用这个API端点的React / Redux / Single Page应用程序。
当用户凭证有效时,负责登录的API端点会使用用户对象(包括访问令牌)响应应用程序。访问令牌后来在应用程序发出的每个请求中使用,以根据API验证用户。
当应用程序从API接收到此用户信息时,会发生以下两件事:1)将操作分派给用户reducer,类似于 ADD_USER
,将此用户包含在用户存储中; 2)用户的访问令牌保留在 localStorage
。
在此之后,任何组件都可以连接到用户reducer并使用持久访问令牌来了解谁是已登录用户,当然,如果您没有访问令牌 localStorage
这意味着用户未登录。
在我们的组件层次结构的顶部,我们有一个组件负责连接到用户reducer,根据持久化的访问令牌获取当前用户 localStorage
,并将此当前用户传递给 React的背景。因此,我们避免依赖于当前用户的每个组件必须连接到用户reducer并从中读取 localStorage
,我们假设这些组件将始终从应用程序的上下文中接收当前用户。
令牌过期等一些挑战会给解决方案带来更多复杂性,但基本上这就是我们这样做的方式,并且它运行良好。