React - Native ' Redux 未捕获错误:操作必须是普通对象。按下按钮时使用自定义中间件进行异步操作

Posted

技术标签:

【中文标题】React - Native \' Redux 未捕获错误:操作必须是普通对象。按下按钮时使用自定义中间件进行异步操作【英文标题】:React - Native ' Redux Uncaught Error: Actions must be plain objects. Use custom middleware for async actions' on button pressReact - Native ' Redux 未捕获错误:操作必须是普通对象。按下按钮时使用自定义中间件进行异步操作 【发布时间】:2020-06-18 15:16:03 【问题描述】:

所以我是 React-Native 和 Redux 的新手。我正在将 Redux 集成到 React-Native 中,一切都运行良好,除了调度操作。每次我尝试调度操作时,我都会收到错误“Redux Uncaught Error: Actions must be plain objects”。使用自定义中间件进行异步操作'。我什至尝试集成 react-thunk,但没有成功。我什至尝试使用store.dispatch(setIsLoggedIn(true)) 直接在商店发货。我的应用程序应该支持登录功能,我想设置状态,以便我知道我的用户是否已登录。

我的商店是这样初始化的:

import createStore, compose, applyMiddleware from 'redux';
import rootReducer from '../reducers/index';
import thunk from 'redux-thunk';

const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, storeEnhancers(applyMiddleware(thunk)));

export default store;

我的减速器是这样的:

import SET_IS_LOGGED_IN, SET_USER, SET_TOKEN from '../actions/index'

const initialState =

    loggedIn: false,
    user: null,
    token: "",

//slice zum removen
function rootReducer(state=initialState, action)

    switch (action.type) 
        case SET_IS_LOGGED_IN:
          return Object.assign(, state, 
            
              loggedIn: true
            )
          break;
          case SET_USER:
        return Object.assign(, state, 
          
              user: action.user
          )
        break;
        case SET_TOKEN:
        return Object.assign(, state, 
          
            token: action.token
          )
        break;
        default:
          // Anweisungen werden ausgeführt,
          // falls keine der case-Klauseln mit expression übereinstimmt
          break;
      
    return state;


export default rootReducer;

我的动作是这样定义的:

export const SET_IS_LOGGED_IN='SET_IS_LOGGED_IN'

export function setIsLoggedIn(value)

    return
    
        type: SET_IS_LOGGED_IN,
        value
    ;


export function setIsLoggedInAsync(value)

    return dispatch =>
    
        setTimeout(() => 
        
            dispatch(setIsLoggedIn(value))
        ,1000);
    ;


export const SET_USER='SET_USER'
export function setUser(user)

    return
    
        type: SET_USER,
        user
    ;


export const SET_TOKEN='SET_TOKEN'

export function setToken(token)

    return
    
        type: SET_TOKEN,
        token
    ;

我的主要组件是这样的:

import React,  Component  from 'react';
import ScrollView, Text, TextInput, View, Button, StyleSheet, Image, TouchableOpacity, Linking  from 'react-native';
import UserLogin from '../model/UserLogin';
import loginCall from '../api/User-Api';
import Logo from '../../assets/logo.png';
import connect from 'react-redux';
import setIsLoggedIn, setUser, setToken from '../redux/actions/index'
import store from '../redux/store/index'

const mapStateToProps=(state)=> (

        test: state.test 
 
)

const mapDispatchToProps = (dispatch) => (

    
        setIsLoggedIn: value => dispatch(setIsLoggedIn(true)),
        setUser: user => dispatch(setUser(user)),
        setToken: token => dispatch(setToken(token)),
    
)

class Login extends Component 

    constructor(props)
        super(props);

        this.state = 
            email: "null",
            password:"null",
            wrongPw : false,
            title: "bla"
          

        this._onPressButton = this._onPressButton.bind(this);
        this._onRegisterButton = this._onRegisterButton.bind(this);

    

    componentDidMount()
    
        console.log(store.getState());
    

    componentWillUnmount()
    
        console.log(store.getState());
    

    _onRegisterButton()
    
        var link = "";
        Linking.canOpenURL(link).then(supported => 
            if (supported) 
              Linking.openURL(link);
             else 
              console.log("Don't know how to open URI: " + this.props.url);
            
          );
    


    _onPressButtonTest() 
    
        store.dispatch(setIsLoggedIn(true))
    

    _onPressButton() 
        //let username = this.state.email;
        this.setState(wrongPw: false);
        var user = new UserLogin();
        user.email = this.state.email;
        user.password = this.state.password;
        loginCall(user).then((response) => 
            
                console.log(response);
                // Set token for api calls const token = response.data;
                if(response.status == 200)
                   
                    console.log(response.data)
                    this.props.navigation.navigate('MainPage') 
                    this.props.setIsLoggedInProp(true);
                    //this.props.setIsLoggedIn(true);
                    //this.props.setUser(user);
                    //this.props.setToken(response.data);
                    // <Text style=styles.forgot>this.props.test</Text>

                
            )
            .catch((error) => 
            

                this.setState(wrongPw: true);
                console.log(error);
            
            );
        


    render() 
        return (
            <View style=styles.container>
                <TouchableOpacity onPress=this._onPressButtonTest.bind(this) style=styles.loginBtn>
                    <Text style=styles.loginText>TESTING</Text>
                </TouchableOpacity>
                <Image source=Logo style=styles.logo/>
                <TextInput style=styles.inputView placeholder='Email' placeholderTextColor="#1F676B"  onChangeText=(value) =>  this.setState(email: value) />
                <TextInput style=styles.inputView secureTextEntry=true placeholder='Password' placeholderTextColor="#1F676B" onChangeText=(value) => this.setState(password: value) />
                this.state.wrongPw && <Text style=styles.error>Email oder Passwort ist ungültig.</Text>
                <TouchableOpacity  onPress=() => this.props.navigation.navigate('PasswortVergessen')>
                    <Text style=styles.forgot>Passwort vergessen?</Text>
                </TouchableOpacity>
                <TouchableOpacity onPress=this._onPressButton.bind(this) style=styles.loginBtn>
                    <Text style=styles.loginText>LOGIN</Text>
                </TouchableOpacity>
                <TouchableOpacity onPress=this._onRegisterButton.bind(this)>
                    <Text style=styles.register>Registrieren</Text>
                </TouchableOpacity>
            </View>
            )
    

//null wenn ich nichts will von states
export default connect(mapStateToProps, mapDispatchToProps)(Login);

const styles = StyleSheet.create(
    container: 
      flex: 1,
      backgroundColor: '#1F676B',
      alignItems: 'center',
      justifyContent: 'center',
    ,

    logo:
        width: 280,
        height: 140,
        marginBottom:30,
      ,

    inputView:
        width:275,
        backgroundColor:"#a5c2c3",
        borderRadius:25,
        height:50,
        marginBottom:20,
        justifyContent:"center",
        padding:10,
        color:"#1F676B",
        fontSize:15,
        fontWeight: "bold"
    ,
    inputText:
        height:50,
        color:"#1F676B"
    ,
    forgot:
        color:"white",
        fontSize:12,
        marginBottom:10,
    ,
    register:
        color:"white",
        fontSize:16,
    ,
    loginText:
        color:"#1F676B",
        fontSize:19,
        fontWeight: "bold"
    ,
    loginBtn:
        width:275,
        backgroundColor:"#ffffff",
        borderRadius:25,
        height:50,
        alignItems:"center",
        justifyContent:"center",
        marginTop:40,
        marginBottom:10
      ,
    error:
        color:"#fff",
        fontSize:19,
        marginBottom:20
    ,

  )

我正在寻找过去几个小时的错误,但似乎无法取得进展。任何提示都表示赞赏。

编辑:所以错误出现在操作中。我的行为定义错误。 这对我来说是这样的:

export function setIsLoggedIn(value)

    const action =
    
        type: SET_IS_LOGGED_IN,
        value
    ;
    return action; 

【问题讨论】:

【参考方案1】:

尝试按照约定 type: SET_IS_LOGGED_IN, payload: value 构建操作。我认为value 试图解构value,而不是在你的动作对象中设置一个新的道具value: true。让我知道它是否有效。

【讨论】:

【参考方案2】:

对于异步操作,您不应执行 dispath 并调度操作,而是将其作为第二个参数传递给 setIsLogedIn 函数


export function setIsLoggedInAsync(value)

    return dispatch =>
    
        setTimeout(() => 
        
            dispatch(setIsLoggedIn(value))
        ,1000);
    ;

你需要在mapDispatchToProps函数中提供这种方式,

 setIsLoggedIn: value => setIsLoggedIn(true)(dispatch), // do this
 // setIsLoggedIn: value => dispatch(setIsLoggedIn(true)) dont

在您的方法中,您正在执行调度,并且 setIsLoggedIn 会返回一个动作对象(带有动作键的对象),而 setIsLoggedIn 不会返回一个动作对象,而是返回一个 thunk,一个函数;。

【讨论】:

以上是关于React - Native ' Redux 未捕获错误:操作必须是普通对象。按下按钮时使用自定义中间件进行异步操作的主要内容,如果未能解决你的问题,请参考以下文章

React Native 已经有了异步存储。为啥我应该在我的 react native 应用中使用 Redux 和 Redux Thunk?

React Native使用Redux总结

在 Redux 中没有 React Navigation 状态的 React Native 中的 Redux

react-native 中的 Redux 错误

React native 和 redux 仍然无法正常工作

React-native + Redux(Combine Reducers):创建状态结构