简体   繁体   English

Redux动作正常,但减速器无效

[英]Redux action is working but reducer is not

Not sure why my reducer is not working. 不知道为什么我的减速机不工作。 I have a console.log in my actions file. 我的操作文件中有一个console.log。 So for example, when I test out a failed login attempt, I see the console log in both the loginFromAPI function and loginFailure function (see in actions.js below) . 因此,例如,当我测试失败的登录尝试时,我同时在loginFromAPI函数和loginFailure函数中看到控制台日志(请参见下面的actions.js) These are outputting what is expected. 这些正在输出预期的结果。 But for some reason, the login reducer is not working. 但是由于某种原因,登录还原器无法正常工作。 When I console.log in the loginReducer.js , I see nothing. 当我在loginReducer.js中进行 console.log时,什么也看不到。 This tells me that although the action is working, the reducer is not. 这告诉我,尽管该动作有效,但减速器却无效。 My redux props do not change from the initial state (I've checked this by outputting to the console). 我的redux道具从初始状态不变(我已经通过输出到控制台检查了它)。 I'd appreciate any help solving this issue. 感谢您为解决此问题所提供的帮助。

Here is the file structure: 这是文件结构:

app
   reducers
      loginReducer.js
      rootReducer.js
   screens
      Login
         Login.js
         index.js
         actions.js
   store
      configureStore.js
App.js
actionTypes.js

File configureStore.js 文件configureStore.js

import { createStore, applyMiddleware } from 'redux';
import app from '../reducers/rootReducer';
import thunk from 'redux-thunk';
import {createLogger} from 'redux-logger';

export default function configureStore() {
    const logger = createLogger();
    let store = createStore(app, applyMiddleware(thunk, logger));
    return store;
}

File rootReducer.js 文件rootReducer.js

import { combineReducers } from 'redux';
import loginReducer, * as fromLogin from './loginReducer';

export default combineReducers({
    login: loginReducer
})

export const getLogin = (state) => fromLogin.getLogin(state.login)

File loginReducer.js 文件loginReducer.js

import { LOGIN, LOGIN_SUCCESS, LOGIN_FAILURE } from '../actionTypes';


const initialState = {
    user: {},
    isFetching: false,
    isLoggedIn: false,
    error: false,
    errorMessage: "",
}

export default function loginReducer(state = initialState, action) {
    console.log(action); <-- I do not see this
    switch(action.type) {
        case LOGIN:
            return {
                ...state,
                isFetching: true,
                user: {}
            }
        case LOGIN_SUCCESS: 
            return {
                ...state, 
                isFetching: false,
                isLoggedIn: true,
                user: action.user
            }
        case LOGIN_FAILURE:
            return {
                isFetching: false,
                error: true,
                errorMessage: action.errorMessage
            }
        default:
            return state
    }
}

export const getLogin = (state) => ({
    user: state.user,
    isFetching: state.isFetching,
    isLoggedIn: state.isLoggedIn,
    error: state.error,
    errorMessage: state.errorMessage
})

File actions.js 文件actions.js

import { LOGIN, LOGIN_SUCCESS, LOGIN_FAILURE } from '../../actionTypes';
import axios from 'axios';

export function loginFromAPI(loginInfo) {
        login();
        axios({
            method: 'POST',
            url: 'SOME_URL_GOES_HERE',
            headers: {
                'Content-Type': 'application/json; charset=utf-8',
            },
            data: JSON.stringify({
                email: loginInfo.email,
                password: loginInfo.password
            }),  
        })
        .then((response) => {
            loginSuccess(response.data);
            console.log(response.data);
        })
        .catch(error => {
            switch(error.response.status) {
                case 404:
                    console.log("No user with that email.");
                    loginFailure("No user with that email.")
                    break;
                case 401: 
                    console.log("Invalid password.");
                    loginFailure("Invalid password.")
                    break;
                default: 
                    console.log("There was an error loggin in");
                    loginFailure("There was an error loggin in");
                    break;
            }

        })

}

function login() {
    return {
        type: LOGIN,
    }
}

function loginSuccess(user) {
    return {
        type: LOGIN_SUCCESS,
        user
    }
}

function loginFailure(errorMessage) {
    console.log(errorMessage); <-- I see this output
    return {
        type: LOGIN_FAILURE,
        errorMessage
    }
}

File index.js 文件index.js

import Login from './Login';
import {connect} from 'react-redux';
import * as actions from './actions';
import {getLogin} from '../../reducers/rootReducer';

const mapStateToProps = (state) => ({
    ...getLogin(state),
})

const mapDispatchToProps = () => ({
    ...actions
})

export default connect(mapStateToProps, mapDispatchToProps)(Login)

File Login.js 文件Login.js

export default class Login extends Component {

  constructor(props) {
    super(props);

    this.state = {
      email: null,
      password: null,
    }
    this.login = this.login.bind(this);
  }

  login() {
    this.props.loginFromAPI({email: this.state.email, password: this.state.password});
    console.log(this.props) <-- This never changes but does show up
  }

  render() {
    let error = this.props.error

    return (
      <ImageBackground source={require('../../assets/Signup.png')} style={styles.container}>
        <View style={styles.content}>

          ...

          Some text input Stuff

          ...

          {error && 
              <Text>{this.props.errorMessage}</Text>
          }

            <Button     
              onPress={this.login}
            />

          ...

    );
  }
}

You do not dispatch your action in mapDispatchToProps. 您不会在mapDispatchToProps中调度动作。 https://redux.js.org/basics/actions https://redux.js.org/basics/actions

So for an action to work, you need to return an object containing the key "type" that matches your reducer switch case. 因此,要使操作生效,您需要返回一个对象,该对象包含与减速器开关盒匹配的键“类型”。

{ type: "MY_ACTION_TYPE" } {类型:“ MY_ACTION_TYPE”}

However your function loginFromAPI is async, and thus you can't just return an object from it. 但是,您的函数loginFromAPI是异步的,因此您不能仅从中返回对象。 To get around this you can use redux middlewares. 为了解决这个问题,您可以使用redux中间件。

Two of the most popular are redux-thunk, and redux-saga. 最受欢迎的两个是redux-thunk和redux-saga。 redux-thunk is much simpler. redux-thunk简单得多。

Thunk example: 厚重的例子:

export function loginFromAPI(loginInfo) {
 return function (dispatch) {
   dispatch(login())

   login()
     .then(res => dispatch(loginSuccess()) // the action you want to dispatch
 }
}

https://www.npmjs.com/package/redux-thunk https://www.npmjs.com/package/redux-thunk

https://github.com/redux-saga/redux-saga https://github.com/redux-saga/redux-saga

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM