3

I've been using React and Redux for the last 2 weeks and I'm not entirely sure of how everything works and after hours of searching about this and not really finding the information I needed I decided to ask

I'm working on a webapp created with React and using redux to handle some things such as the authentication state. In this case, I'm using Google Authentication (passportjs + google plus api). I'm getting the user's info from my mongoDB and storing it in the state of the redux store. That works fine.

Then, from a specific component, I'm currently using:

function mapStateToProps({ auth }) {
    return { auth };
}

export default connect(mapStateToProps) (ExampleComponent);

This works just fine, the issue though, comes when I try to store this props in the component's state. I've tried setting the state on the component's constructor and it just sets things as null.

Apparently, and here is what I don't really understand, the props start by containing a null 'auth' field and then a second later, the auth gets filled with that mapStateToProps info.

If I call those props in the render method of the component, it works just fine, but if I want to store the value of this.props.auth in the component's state, it won't work.

Am I thinking about all this in a wrong way? Am I not understanding how the flow works or...? I don't get why the props start by beeing null and get modified later.

I've also tried to have a function that modifies the state with props values and to call that function from inside the render method of the component (which already contains the props) but it creates an infinite loop.

    setInitialStates() {
          this.setState({
                val1: this.props.auth.val1,
                val2: this.props.auth.val2,
                val3: this.props.auth.val3
          });
    }

.

render() {
        if(this.props.auth) {
            this.setInitialStates();
        }
        ...
    }

I've also tried calling this setState in ComponentDidMount, but it doesn't seem to do anything!

componentDidMount() {
        if(this.props.auth) {
            this.setState({
                val1: this.props.auth.val1,
                val2: this.props.auth.val2,
                val3: this.props.auth.val3
            });
        }
    }

Can someone with a better understanding of react and redux through some light on this please? Thanks!

p3rzival
  • 33
  • 1
  • 3
  • You can try setting state in `componentWillReceiveProps` lifecycle. BTW why are you setting state while you can always set an action to modify your props in reducer? – Triyugi Narayan Mani Apr 04 '18 at 09:36
  • I would just operate directly on props rather then assigning it to store. At every update of redux-store You have to take care on fresh component state which causes creating boilerplate code imo – Michal Cholewiński Apr 04 '18 at 09:36
  • Just a side note, you should not set state in `render()`. When you call `setState()` it triggers a `render`, thus loops. – Dan Apr 04 '18 at 09:41
  • it's the problem with async flow that you have. Take a look at [`this`](https://stackoverflow.com/questions/27192621/reactjs-async-rendering-of-components?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa) answer – The Reason Apr 04 '18 at 09:45
  • Wow, thank you very much for all your help guys! @TriyugiNarayanMani you're right, using that, works just fine! The only concern I have is that the method seems to be UNSAFE? https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops – p3rzival Apr 04 '18 at 09:55
  • @BorjaLeiva check this: [How to use lifecycle method getDerivedStateFromProps as opposed to componentWillReceiveProps](https://stackoverflow.com/questions/49617486/how-to-use-lifecycle-method-getderivedstatefromprops-as-opposed-to-componentwill) – Triyugi Narayan Mani Apr 04 '18 at 10:03
  • @p3rzival You seems to missed the link to this in above comment. – Triyugi Narayan Mani Apr 04 '18 at 10:16
  • @TriyugiNarayanMani sorry for answering then! Newbie! Didn't know you couldn't do that to follow up with a question. I'm going to create a new one but I have to wait 90 min so I'll post the link to the other question here :) Is it fine if I update the original question adding this question in there? – p3rzival Apr 04 '18 at 10:29
  • @p3rzival No problem, you will be acquainted with this platform soon. Yes its perfectly fine to post new question with the link of this question. – Triyugi Narayan Mani Apr 04 '18 at 11:02

3 Answers3

2

componentDidMount fire once, after component is mounted. But redux send new props to your component every time redux state updated and your component use this state fields. componentWillReceiveProps will check every new props coming.

componentWillReceiveProps(nextProps) {
      this.setState({
            val1: nextProps.auth.val1,
            val2: nextProps.auth.val2,
            val3: nextProps.auth.val3
      });
}

Note

This lifecycle is deprecated now and is called UNSAFE_componentWillReceiveProps. Check the link below to see alternatives.

https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops

Andrii Starusiev
  • 7,564
  • 2
  • 28
  • 37
1

componetDidMount will get invoked only when the component is mounted. so you have to use componentWillReceiveProps, which gets invoked on props changes.

For better understanding check this out: https://levelup.gitconnected.com/componentdidmakesense-react-lifecycle-explanation-393dcb19e459

0

I'm facing a problem like you and I realize that you can use componentWillReceiveProps or getDerivedStateFromProps but you need to trigger local state change to map new props. I try some case and I dont know when it auto change or not so I write this funtions to re-render whenever dispatch action:

setCount() {
    let {count} = this.state;
    this.setState({count: count++});
}

This is not best solution but this is the best way to do this easily.

May'Habit
  • 1,334
  • 12
  • 18