Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do I call setState for redux values?

I'm pretty new to react native and async programming, and trying to understand how to "sync" redux state values and local state values.

For example, I have a text field "aboutMe" stored server side, and using mapStateToProps to place it into props:

   const mapStateToProps = (state) => {
      return { aboutMe: state.aboutMe };
   }

In render, I have a TextInput I'm using so that the user can edit this field, and I would like to default to what is saved on the server side:

         <TextInput
          onChangeText={(aboutMe) => { 
              this.setState({aboutMe});
          }}
          value={this.state.aboutMe}
        />

Basically, somewhere I need to call

      this.setState({ aboutMe: this.props.aboutMe });

Where is the right place to this? I was trying to use componentWillReceiveProps, but that lifecycle method is not called on constructor, so I would need to setState twice (in constructor and in componentWillReceiveProps).

Is there another way to do this? I feel like this is a pretty generic problem that a lot of react native developers have solved but I couldn't find a generally accepted way online.

Thanks!

Edit:

I have alot of TextInputs, so I have a separate button to call the action to save the variables:

    <Button onPress={()=>{ 
      this.props.saveUserInput(this.state.aboutMe, 
      this.state.name, this.state.address, ....}}>
      <Text> Save changes </Text>
    </Button>

From the comments, I understand that it's possible to call the save action onChangeText... but is that too much traffic back and forth? Would it be better to save all of the variables locally to state and then call a save for everything at once? Also, what if the user would like to "cancel" instead of save? The changes would have been already saved and we will not be able to discard changes?

like image 709
React Beginner Avatar asked Dec 18 '22 00:12

React Beginner


1 Answers

1) If your component is a controlled component (you need state in it) and the request is asynchronous indeed you have to set the state in the componentWillReceiveProps like this:

class ExampleComp extends Component {
  constructor(props) {
    super(props);
    this.state = {
      aboutMe: ""
    }
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      aboutMe: nextProps.aboutMe,
    });
  }

  render() {
    return (
      <TextInput
        onChangeText={(aboutMe) => {
          this.setState({aboutMe});
        }}
        value={this.state.aboutMe}
      />
    );
  }
}

Keep in mind the key here is that the state must remain the single source of truth from now on.

2) The other option would be, you can wait until the request is finished in the parent component and then set the aboutMe in your constructor, this way you can avoid componentWillReceiveProps. For example:

class ParentComp extends Component {

  render() {
    return (
      <div>
        {this.props.aboutMe && <ExampleComp/>}
      </div>
    );
  }
}

class ExampleComp extends Component {
  constructor(props) {
    super(props);
    this.state = {
      aboutMe: props.aboutMe
    }
  }

  render() {
    return (
      <TextInput
        onChangeText={(aboutMe) => {
          this.setState({aboutMe});
        }}
        value={this.state.aboutMe}
      />
    );
  }
}

The downside of this is that the text input won't be shown until the request is finished.

like image 158
Shota Avatar answered Dec 31 '22 01:12

Shota