2

I have a simple redux action and reducer that changes state without making any sort of web service request:

// Action
export const setMyState = (value) => {
  return {
    type: 'SET_STATE',
    payload: value
  };
};

// Reducer
export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case 'SET_STATE':
      return { myState: action.payload }
  }
}

When I set the state via the action in my react component and immediately call that state from the redux prop binding, I do not get the current state:

import React from 'react';
import { connect } from 'react-redux';
import { setMyState } from '../actions';

class MyScreen extends React.Component {

  componentWillMount() {
    this.props.setMyState('value');
    console.log(this.props.myState);
  }
}

const mapStateToProps = state => {
  const { myState } = state;
  return myState;
};

export default connect(mapStateToProps, { setMyState })(MyScreen);

I understand that render will be called again when the redux state and binded props change, but what I'm trying to do is fire off another Redux action based on the resulting state. My options appear to be:

  1. Figure out how to latest Redux state in React immediately after state change

  2. Fire off a redux action in the reducer instead, which sounds like an anti-pattern.

  3. Set some sort of state in my component or redux that the action should be fired on the next render, which seems clunky.

tassock
  • 1,633
  • 1
  • 17
  • 32
  • You're just missing `componentWillReceiveProps` which will accept the new change from Redux, at which point you can `setState` again. – lux May 18 '18 at 01:56

3 Answers3

1

config your reducer like:

switch (action.type) {
  case 'SET_STATE':
    return {
      ...state,
      loading: true,
    };

  case 'SET_STATE_SUCCESS':
    return {
      ...state,
      loading: false,
      payload: value
    };
}

and then in your component listen to

this.props.myState.loading

then trigger your action if (loading) and so on!

0

What are you using this Redux state for?

If you are trying to access the data you had just set in the Redux state or if it's data that's already sitting in the Redux state you could dispatch both calls at the same time.

If you need to make the call because there is some work done to the data while setting it in the Redux state (I recommend doing this work in the action not the reducer) then componentWillReceiveProps(nextProps) will do what you need. You can compare the current props with the next props and trigger another update to the Redux state.

The best way to do this would probably be to use a Redux middleware.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
JoshD
  • 41
  • 4
  • Thanks for your response. I decided Redux wasn't a good use case for my particular problem. Also, it looks like componentWillReceiveProps is no longer the preferred lifecycle method to do something like you're talking about: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops – tassock May 23 '18 at 17:49
-1

My solution is to use event loop handles the update, not the call stack. In particular for your case you the implementation would include setTimeout(() => {}); as the following:

import React from 'react';
import { connect } from 'react-redux';
import { setMyState } from '../actions';

class MyScreen extends React.Component {

  componentWillMount() {
    setTimeout(() => { this.props.setMyState('value'); },0);
    setTimeout(() => { console.log(this.props.myState); },0);
  }
}

const mapStateToProps = state => {
  const { myState } = state;
  return myState;
};

export default connect(mapStateToProps, { setMyState })(MyScreen);
Roman
  • 19,236
  • 15
  • 93
  • 97