Redux减速器被调用两次

时间:2018-03-27 19:28:55

标签: javascript reactjs react-native react-redux

我正在使用Redux开发React Native应用程序。

该应用程序具有注册屏幕,其格式为:

(lldb) expr NSString *$myString = [NSString stringWithUTF8String: "my new string"]
(lldb) po $myString
my new string

另外,我已经创建了一些动作:

1)import React from 'react'; import { Alert, Button, KeyboardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import {connect} from "react-redux"; import {register} from "../redux/actions/Registration"; import {REGISTER} from "../redux/constants/ActionTypes"; import Loader from "./Loader"; const mapStateToProps = (state, ownProps) => { return { isLoggedIn: state.registration.isLoggedIn, token: state.registration.token, isLoading: state.common.isLoading, error: state.common.error }; }; const mapDispatchToProps = (dispatch) => { return { onRegister: (username, password, firstName, lastName) => { dispatch(register(username, password, firstName, lastName)); } } }; @connect(mapStateToProps, mapDispatchToProps) export default class RegistrationForm extends React.Component { constructor(props) { super(props); this.state = { route: REGISTER, email: '', password: '', firstName: '', lastName: '', isLoading: false } } register(e) { this.props.onRegister( this.state.email, this.state.password, this.state.firstName, this.state.lastName ); e.preventDefault(); } componentDidUpdate() { if (this.props.error != null && this.props.error !== undefined && this.props.error !== '') { setTimeout(() => Alert.alert(this.props.error), 600); } } render() { const {isLoading} = this.props; return ( <View style={styles.container}> <KeyboardAvoidingView style={styles.registration_form} behaviour="padding"> <Loader loading={isLoading}/> <TextInput style={styles.text_input} placeholder="First Name" placeholderTextColor="white" underlineColorAndroid={'transparent'} onChangeText={(text) => this.setState({firstName: text})}/> <TextInput style={styles.text_input} placeholder="Last Name" placeholderTextColor="white" underlineColorAndroid={'transparent'} onChangeText={(text) => this.setState({lastName: text})}/> <TextInput style={styles.text_input} placeholder="Email" placeholderTextColor="white" underlineColorAndroid={'transparent'} keyboardType="email-address" onChangeText={(text) => this.setState({email: text})}/> <TextInput style={styles.text_input} placeholder="Password" placeholderTextColor="white" underlineColorAndroid={'transparent'} onChangeText={(text) => this.setState({password: text})} secureTextEntry={true}/> <TouchableOpacity style={styles.button} onPress={(e) => this.register(e)}> <Text style={styles.btn_text}>Sign up</Text> </TouchableOpacity> <Button buttonStyle={{marginTop: 40}} backgroundColor="transparent" textStyle={{color: "#fff"}} title="Login" onPress={() => this.props.navigation.navigate('Login')}/> </KeyboardAvoidingView> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#36485f', paddingLeft: 60, paddingRight: 60 }, registration_form: { alignSelf: 'stretch', }, text_input: { alignSelf: 'stretch', height: 40, marginBottom: 30, color: '#fff', borderBottomColor: '#f8f8f8', borderBottomWidth: 1 }, button: { alignSelf: 'stretch', alignItems: 'center', padding: 20, backgroundColor: '#59cbbd', marginTop: 30 }, btn_text: { color: '#fff', fontWeight: 'bold' } });

Common.js

2)import {FAILED, LOADING} from "../constants/ActionTypes"; export const loading = (isLoading) => { return { type: LOADING, isLoading: isLoading } }; export const failed = (error) => { return { type: FAILED, error: error } };

Registration.js

减速器:

1)import {userService} from "../../service/UserService"; import {REGISTER} from "../constants/ActionTypes"; import {failed, loading} from "./Common"; export const register = (username, password, firstName, lastName) => { return dispatch => { dispatch(loading(true)); userService.register(username, password, firstName, lastName) .then(resp => { dispatch(loading(false)); dispatch({ type: REGISTER, token: resp.json().token, error: null }); } ) .catch(err => { dispatch(loading(false)); dispatch(failed(err.message)) }) }; };

Common.js

2)import {FAILED, LOADING, REGISTER} from "../constants/ActionTypes"; const defaultState = { isLoading: false, error: null }; export default function reducer(state = defaultState, action) { console.log('COMMON STATE: ', state); console.log('COMMON ACTION: ', action); switch (action.type) { case LOADING: return { ... state, isLoading: action.isLoading }; case FAILED: return { ... state, error: action.error }; default: return state; } }

Registration.js

3)import {FAILED, LOADING, REGISTER} from "../constants/ActionTypes"; const defaultState = { isLoggedIn: false, token: null }; export default function reducer(state = defaultState, action) { console.log('REGISTER STATE: ', state); console.log('REGISTER ACTION: ', action); switch (action.type) { case REGISTER: return Object.assign({}, state, { isLoggedIn: action.isLoggedIn, token: action.token }); default: return state; } }

Index.js

当我第一次单击“注册”组件上的“注册”按钮时 - 一切正常 - 它显示一个微调器,然后显示一个警告。

当我第二次点击“注册”按钮(或第三次等)时,它还会显示一个微调器,然后逐个打开两个警告。

我的期望:每次点击应用程序都应该只显示一个警报。

在控制台中,我看到以下输出:

import { combineReducers } from 'redux';
import registration from './Registration';
import login from './Login';
import common from './Common'

const rootReducer = combineReducers({
    registration,
    login,
    common
});

export default rootReducer;

因此减速器被召唤两次。如何解决这个问题?或者如何防止打开第二个警报弹出窗口?

更新

您可以在GitHub上找到该项目的源代码:https://github.com/YashchenkoN/money-observer-client

更新2。 从@Chase DeAnda改变后,它以这种方式看待:

1 个答案:

答案 0 :(得分:2)

register功能中,您需要检查props以确定用户是否已注册:

register(e) {
  e.preventDefault();
  if (!this.props.token) {
    this.props.onRegister(
      this.state.email,
      this.state.password,
      this.state.firstName,
      this.state.lastName
    );
  } else {
    // User already registered
    // Redirect to login page
  }
}

修改

好吧,我想我现在看到了问题。您正在使用componentDidUpdate生命周期方法。这种方法被称为每次一个州或道具传递给它,不一定只有它们已经改变。您遇到的问题是您没有检查this.props.error实际上是否与您已经显示的第一个错误不同。将其更改为:

componentDidUpdate(prevProps,prevState) {
    if(prevProps.error !== this.props.error && this.props.error){
        setTimeout(() => Alert.alert(this.props.error), 600);
    }
}

由于您有多个Reducer对失败的XHR请求作出反应,因此您的组件将从多个操作中获取传递给它的props。您需要确保只显示错误,如果它与之前传递的错误不同。