0

I have been looking for an elegant (and correct) way to handle logging in for a Redux application. Currently the the user is directed to a login component/container where he see's a form with username and password. Then when he clicks on submit I call an async login function and when the promise is fulfilled then I dispatch a loginSuccess and also a replacePath call. The following is some pseudo code:

submit(e) {
   login(username, password)
      .then(function (user) {
         dispatch(loginSuccess(user));
         dispatch(replacePath('/');
      });
}

This works but I'm not sure it's best practice. Anyone have any better implementations?

4

1 回答 1

1

通常认为在组件内调用 dispatch 是不好的做法,除非它是连接到 store 的顶级容器。

我建议遵循 Dan Abramov 在文档中提供的示例,最值得注意的是async Reddit post fetching example。看看他是如何处理临时请求的posts.isFetching

因为我知道 StackOverflow 不喜欢链接,所以这是一个简化的示例(在 ES6 中):


这些是行动:

// Actions

import fetch from 'isomorphic-fetch';
import * as types from '../constants/actionTypes.js';
var requestAuth = function() {
    return {
        type: type.REQUEST_AUTH
    }
};

var authSuccess = function(response) {
    return {
        type: type.AUTH_SUCCESS,
        response: response
    }
};

var authFail = function(response) {
    return {
        type: type.AUTH_FAIL,
        response: response
    }
};

var authenticate = function(username, password) {
    var fetchOptions = {
        method: 'post',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({username: username, password: password})
    };
    var uri = '/api/path/to/your/login/backend';
    return dispatch => {
        dispatch(requestAuth);
        return fetch(uri, fetchOptions)
            .then(response => {
                if (resopnse.status === 200) {
                    dispatch(authSuccess(response));
                    // Do any other login success work here
                    // like redirecting the user
                } else {
                    dispatch(authFail(response));
                }
            }
    }
};

接下来是减速机:

// Reducer
import { combineReducers } from 'redux';
import { REQUEST_AUTH, AUTH_SUCCESS, AUTH_FAIL } from '../actions/login';

function login(state = {
    isAuthenticating: false,
    isLoggedIn: false,
    authenticationToken: '',
    authError: null
    .....,   // whatever other state vars you need
    .....
    }, action) {
        switch(action.type) {
            case REQUEST_AUTH:
                return Object.assign({}, state, {
                    isAuthenticating: true
                });
                break;
            case AUTH_SUCCESS:
                return Object.assign({}, state, {
                    isAuthenticating: false,
                    isLoggedIn: true,
                    authenticationToken: action.response.token
                });
                break;
            case AUTH_FAIL:
                return Object.assign({}, state, {
                    isAuthenticating: false,
                    authError: action.response.error
                });
            break;
           default:
                return state;

    }
}

最后是组件方法

// Component Method
// authenticate() should be wrapped in bindActionCreators()
// and passed down as a prop
function handleSubmit(username, password) {
    if (isValid(username) && isValid(password) {
        authenticate(username, password);
    }
}

tl;dr 您的用户输入他们的凭据,这应该是状态的一部分(此处未显示)。组件中的onClick 调用handleSubmit(),它调度authenticate()。Authenticate 调度 requestAuth() 更新状态以向您的用户显示正在处理请求(显示加载微调器或其他内容)。一旦您对后端的 AJAX 调用返回了身份验证结果,您就会分派 authSuccess() 或 authFail() 来更新状态并通知用户他们的请求是否成功。

于 2016-01-27T02:01:25.687 回答