1
votes

I'm having an issue with a React Native application that uses Redux, and I've struggling to figure out the cause.

When the Redux state is changed by a dispatch in component A, component B doesn't show the most up to date value of the Redux state. For example, say I click a button in component A to change a Redux value from 0 to 1, it will show 0 in component B, but when I click the button to add 1 to make it 2, component B will show 1. Below is an example of my code. When I click on the TouchableOpacity in component A, it should change this.props.screen from 1 (the initial state) to 0. In component B, I have a regular console.log of this.props.screen, and a console.log inside a setTimeout with 50 milliseconds. Inside the console, the console.log in the setTimeout has the correct value of 0 when hit, however the one outside it still shows 1. Similarly, the text rendered in component B will show 1 as well. If I click the button again, it will then show 0.

I've included the relevant action and reducer from my code. At first, I thought it might be a mutation, but it seemed that can only happen with objects and arrays (I'm only using a number). I would appreciate some help figuring out how to have the text rendered in component B reflect the most current value. Thanks in advance!

Component A

    import { connect } from "react-redux";
    import { setScreen } from "../redux/Actions";

    class Header extends Component {


      componentWillReceiveProps(nextProps){
        setTimeout(() => { this.logoHide() },10);
        this.props.scrollLocation < 10 ? this.changeTransparency(0) : this.changeTransparency(.9);
      }

      setScreen(screen){
        this.props.setScreen(screen);
      }

      render() {

        var {height, width} = Dimensions.get('window');

        return (
          <View>    
              <TouchableOpacity onPress={() => this.setScreen(0)}>
                <Text>Click Me</Text>
              </TouchableOpacity>
          </View>
        );
      }
    }
const mapStateToProps = state => {
  return {
    height: state.height,
    platform: state.platform,
    screen: state.screen,
    scrollLocation: state.scrollLocation
  };
};

const mapDispatchToProps = dispatch => {
  return {
    setScreen: (value) => dispatch(setScreen(value))
  };
};

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

Redux Action

import { SET_SCREEN } from './Constants';
    export const setScreenDispatcher = (value) => ({ type: SET_SCREEN, screen: value});
    export const setScreen = (value) => {
        return (dispatch) => {
            dispatch(setScreenDispatcher(value));
        }
    }

Redux Reducer

import { combineReducers } from 'redux';
import { SET_SCREEN } from "./Constants";

const initialState = []

const screen = (state = 1, action) => {
  switch (action.type) {
    case SET_SCREEN:
      return action.screen;
    default:
      return state;
  }
};

// COMBINE REDUCERS //
export default combineReducers({
  screen
});

Component B

import { connect } from "react-redux";

class VisibleMenus extends Component {

componentWillUpdate(){
    console.log(this.props.screen);
    setTimeout(() => {console.log(this.props.screen)},50);
    }
  }
 render() {

    return (
      <View>
    <Text>{this.props.screen}</Text>
 </View>
    );
  }
}
const mapStateToProps = state => {
  return {
    screen: state.screen
  };
};

const mapDispatchToProps = dispatch => {
  return {

  };
};

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

App.js

import React, {Component} from 'react';

import { Provider } from "react-redux";

import VisibleMenus from './VisibleMenus';

import { Store } from "./redux/Store";

const store = Store();

export default class App extends Component {

  render() {

    return (

      <Provider store={store}>

        <VisibleMenus />

      </Provider>

    );

  }

}

Store.js

// REDUX STORE //

import { createStore, applyMiddleware } from "redux";

import rootReducer from "./Reducers";

import ReduxThunk from 'redux-thunk'



export const Store = (initialState) => {

    return createStore(

    rootReducer,

        initialState,

        applyMiddleware(ReduxThunk)

    );

}
1

1 Answers

0
votes

For anyone who runs into this, I thought I'd share how I fixed it.

I researched mutations, and I definitely wasn't mutating the state, yet my components would not update when the Redux store changed.

I tried using both componentWillUpdate() and componentWillReceiveProps() but both didn't change anything. However, I was doing a comparison between this.props.screen and this.state.screen which ended up being my issue.

I should have been doing a comparison with nextProps.screen and this.state.screen inside a componentWillReceiveProps(nextProps) which ended up fixing everything.

I do want to thank Hashith for his help.