ilkengin
ilkengin

Reputation: 301

"Cannot update during an existing state transition" Error in React Native and Redux with External API

I am writing a React Native app and using Redux.

I have followed this tutorial.

I have faced with the following warning message:

Warning: Cannot update during an existing state transition (such as within 'render' or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to 'componentWillMount'

Here is what I have:

MyComponent.js

import React from 'react';
import { login } from './actions'
import { connect } from 'react-redux';
import { View, Text } from 'react-native';
import { Button } from 'native-base';

class MyComponent extends React.Component {
  render() {
    return(
      <View>
        <Button onPress={() => this.props.login("username","password")}>
          <Text>
            Login!
          <Text>
        </Button>
      </View>
    )
  }
}

function mapStateToProps(state) {
  return { state: state.login }
}

function mapDispatchToProps(dispatch) {
  return {
    login: (username, password) => dispatch(login(username, password))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);

App.js

import React, { Component } from 'react';
import MyComponent from './MyComponent';

import { Provider } from 'react-redux';

import configureStore from './configureStore';
import Route from './config/Router';

export default class App extends Component {
  render() {
    let store = configureStore();
    return (
      <Provider store={store}>
        <MyComponent />
      </Provider>
    );
  }
}

configureStore.js

import { createStore } from 'redux';
import reducers from './reducers';
import thunk from 'redux-thunk';

export default function configureStore() {
  let store = createStore(reducers, applyMiddleware(thunk));
  return store;
}

reducers.js

import * from './constants'
import { combineReducers } from 'redux';

const initialState = {
  isLoggedIn: false,
  isLoggingIn: false,
  username: '',
  error: false
};

function loginReducer(state = initialState, action) {
  console.log('Reducer is called.');
  console.log('Action is ' + JSON.stringify(action));
  console.log('state is ' + JSON.stringify(state));
  switch (action.type) {
    case LOGGING_IN:
      return {
        ...state,
        isLoggedIn: false,
        isLoggingIn: true,
        username: '',
        error: false
      }
    case LOG_IN_SUCCESS:
      return {
        ...state,
        isLoggedIn: true,
        isLoggingIn: false,
        username: action.data.username,
        error: false
      }
    case LOG_IN_FAILURE:
      return {
        ...state,
        isLoggedIn: false,
        isLoggingIn: false,
        username: '',
        error: true
      }
   }
}

export default rootReducer = combineReducers({
  loginReducer,
});

actions.js

import * './constants'
import { Actions } from 'react-native-router-flux';

export function login(username, password) {
  return (dispatch) => {
    dispatch(loggingIn())
    //here will be some API ASYNC CALLS! 
    //depending on the result we will dispatch again!
    myService.login(username,password).done((result) => {
      if(result !== null) {
        dispatch(loginSuccess(result))
      } else {
        dispatch(loginFailure())
      }
    })
  }
}

function loggingIn() {
  return {
    type: LOGGING_IN
  }
}

function loginSuccess(data) {
  return {
    type: LOG_IN_SUCCESS,
    data: data
  }
}

function loginFailure() {
  return {
    type: LOG_IN_FAILURE
  }
}

I have debugged the code. I have seen that the warning comes right after first dispatch call! ( dispatch(loggingIn()) )

So, I don't know what the problem is.

I also wonder if this is the true use of redux and async api calls. Can you help me? Thanks a lot.

Upvotes: 1

Views: 4355

Answers (2)

Eduard
Eduard

Reputation: 9185

As far as I recall from my experience, this error usually appears when you are trying to update something in your render method, which is prohibited.

Verify that it is not happening in your app.

UPD: Try creating a function above the render method that calls this.props.login instead of doing it inside mapDispatchToProps. And add your the login action creator instead of mapDispatchToProps as a second argument to the connect function.

Upvotes: 1

Hana Alaydrus
Hana Alaydrus

Reputation: 2220

I think something wrong here

function mapStateToProps(state) {
  return { state: state.login }
}

Should be

function mapStateToProps(state) {
  return { loginReducer: state.loginReducer }
}

Upvotes: 2

Related Questions