Jothi Kannan
Jothi Kannan

Reputation: 3358

react native redux state update but not rendering in a component

I have 2 components named A and B, In B I have a list of Languages to be selected and updated in component A. I am using Redux for state management when I change the Language from the list I can see that the states are updated(using redux-logger to get logs). But the problem is when I go back to Component A using react-navigation the updated state value is not updated I can see only the old value of state only

ScreenA.js

class ScreenA extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      selectedLanguage: this.props.state.defaultLangName
    }
  }

  render(
       return (
            <Container>
            <Content  style={{  backgroundColor: item.backgroundColor }}>
              <View style={styles.logoContainer}>
              <Text>test page</Text>
              </View>

            <View style={styles.cardParent}>
              <View style={styles.card}>
              <Item style={styles.listItem}>
                <Button transparent style={styles.contentChecked} onPress={() => this._openLang()}>
                  <Text style={styles.listbtn}>{this.state.selectedLanguage}</Text>
                  <Icon name='ios-arrow-forward' style={styles.iconChecked}/>
                </Button>   
              </Item>
              </View>
              </View>
            </Content>
        </Container>
          );
  )

}

export default connect(
    state => ({ state : state.introauthenticate }),
    dispatch => ({
        actions: bindActionCreators(introActions, dispatch)
    })
  )(ScreenA);

ScreenB.js

class ScreenB extends Component {

    constructor(props){
      super(props);
      this.state = {
              langChecked: '0'
          };
    }


    FlatListItemSeparator = () => {
        return (
          <View
            style={{
              height: 1,
              width: "100%",
              backgroundColor: "#999",
            }}
          />
        );
    }

    _selectLanguage (val, name){
      this.setState({ langChecked: val });
      this.props.actions.changeLanguage(val,name, this.props.navigation.navigate);
      //this.props.navigation.navigate('Intro');
    }

    renderItem = (item )=> {
      return(
        <TouchableHighlight
            style={styles.boxSelect}
            underlayColor="transparent"
            onPress={() => this._selectLanguage(item.Value, item.Name)}
        >
            <View style={styles.contentChecked}>
              <Text style={styles.item}  > {item.Name} </Text>
              {this.state.langChecked === item.Value && <Icon name="ios-checkmark-circle" style={styles.iconChecked}/>}
            </View>
         </TouchableHighlight>
      )
    }

    render() {
      return (
          <Container>
          <Header>
            <Left>
              <Button transparent onPress={() => this.props.navigation.goBack()}>
                <Icon name='ios-arrow-back' />
              </Button>
            </Left>
            <Body>
              <Title>Languages</Title>
            </Body>
            <Right />
          </Header>        
        <Content>
        <FlatList
         data={ langs }
         keyExtractor={(item) => item.Value}
         ItemSeparatorComponent = {this.FlatListItemSeparator}
         renderItem={({item}) => this.renderItem(item)}
        />
        </Content>
      </Container>
      );
    }
  }

  export default connect(
    state => ({ state: state.introauthenticate }),
    dispatch => ({
        actions: bindActionCreators(introActions, dispatch)
    })
  )(ScreenB);

reducer.js

export const CHANGE_LANGUAGE = "CHANGE_LANGUAGE";

export function changeLanguage(langValue,langName,navigateTo) { // Fake authentication function
  return async dispatch => {
      try {
          if (langValue && langName) { //If the email and password matches
              const session = { langValue : langValue,langName:langName } // Create a fake token for authentication

              setTimeout(() => { // Add a delay for faking a asynchronous request
                  dispatch(setLanguage(session)) // Dispatch a successful sign in after 1.5 seconds
                  navigateTo('Intro') // If successfull login navigate to the authenticated screen
              }, 1500)
          }  
      } catch (err) { // When something goes wrong
          console.log(err)

      }
  };
} 


function setLanguage(lang){
  return {
      type: types.CHANGE_LANGUAGE,
      data: {
          lang: lang
      }
  };
}

const initialsliderState = {
    defaultLang:'en',
    defaultLangName:'English',
  };

  export default function introauthenticate(state = initialsliderState, action = {}) {

    switch (action.type) {
        case types.CHANGE_LANGUAGE: 
        return { 
          ...state,
          defaultLang: action.data.lang.langValue,
          defaultLangName: action.data.lang.langName,
        };
      default:
        return state;
    }
  }

Logger:

LOG  %c prev state  "introauthenticate": {"defaultLang": "nl", "defaultLangName": "Deutsch", "isAuthSlider": false, "requestingsliderRestore": false}
LOG  %c action      {"data": {"lang": {"langName": "English", "langValue": "en"}}, "type": "CHANGE_LANGUAGE"}
LOG  %c next state "introauthenticate": {"defaultLang": "en", "defaultLangName": "English", "isAuthSlider": false, "requestingsliderRestore": false}}

Upvotes: 0

Views: 141

Answers (1)

trixn
trixn

Reputation: 16354

You are initializing the state of ScreenA with a value passed as a prop and never update it. As you are using redux to store the current language you do not need any state in ScreenA. When you connect a component you pass it the relevant data from your store as props. It seems like you are trying to "override" the state by passing it in as state but that does not update the state as it will be in this.props.state rather then in this.state. What you need to do is to just pass the language as a prop to ScreenA:

export default connect(
    state => ({ selectedLanguage : state.introauthenticate.defaultLang }),
    dispatch => ({
        actions: bindActionCreators(introActions, dispatch)
    })
)(ScreenA);

and then read the selected language from props:

<Text style={styles.listbtn}>{this.props.selectedLanguage}</Text>

When you update your store the component will re-render with the new language. You do not need any additional state in the component itself for data that you have in your redux store.

Upvotes: 1

Related Questions