0

So as I understand, a component will re-render when there has been a change in props and componentWillMount shall run before re-rendering. At the moment my constructor and componentWillMount run as expected, but then the question prop changes which I need to update the user score state, but this change in question prop doesn't trigger the constructor or componentWillMount. As I shouldn't update the state inside the render function (the only place so far that I have been able to get access to the updated question prop), how can I make react recognise this change in it's props and then update the state? Hope that's understandable.

Here is my container

class FullTimeScoreContainer extends Component<Props, State> {

    constructor(props: Props) {
        super(props)
        this.state = {
            userHomeScore: 1,
            userAwayScore: 1
        }
    }

    componentWillMount() {
        getFTSAnswerStatus(this.props.question).then(foundScores => {
            if ( foundScores.userHomeScore ) {
                this.setState({
                    userHomeScore: foundScores.userHomeScore,
                    userAwayScore: foundScores.userAwayScore
                });
            }
        })
    }

    render() {
        const { option, question, questionIndex, user, configs, renderAs, showNextQuestionAfterFTS, total} = this.props;

        // check if question is active or not
        let ComponentClass;
        if ( question[0].active ) {
            ComponentClass = FullTimeScoreActive;
        } else {
            ComponentClass = FullTimeScoreLocked;
        }

        const changeScoreState = (team, val) => {
            switch (team) {
                case "home":
                    this.setState( (prevState) => ({ userHomeScore: prevState.userHomeScore + val }) );
                    break;
                case "away":
                    this.setState( (prevState) => ({ userAwayScore: prevState.userAwayScore + val }) );
                    break;
                default:
                    throw new Error("unrecognised team to change score state")
            }
        }

        const onClickCallback = () => {
            const p = this.props;
            const s = this.state;
            p.showNextQuestionAfterFTS();
            p.recordFullTimeScoreAnswer(s.userHomeScore, s.userAwayScore, p.question, p.questionIndex, p.user, p.configs)
        }

        return (
            <ComponentClass
                imgSrc={imgSrc}
                user={user}
                answerStatus={answerStatus}
                question={question}
                onClickCallback={onClickCallback}
                questionIndex={questionIndex}
                total={total}
                configs={configs}
                userScores={this.state}
                changeScoreState={changeScoreState}
            />
        )
    }
}

const mapStateToProps = state => {
    return {
        configs: state.configs,
        user: state.user
    };
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({ recordFullTimeScoreAnswer, showNextQuestionAfterFTS }, dispatch);
};

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

export { FullTimeScoreContainer }
Ayo K
  • 1,719
  • 2
  • 22
  • 34
jSutcliffe90
  • 323
  • 2
  • 5
  • 19
  • I'm not sure about the question, but I think you are looking for `componentDidMount` – BrTkCa Feb 14 '18 at 16:17
  • componentDidMount would be better to use than `componentWillMount` – Tim Han Feb 14 '18 at 16:24
  • Thanks for your comments guys, I have tried both and it hasn't worked. the constructor and mounting functions have outlived their lifecycle by the time the question prop has been updated – jSutcliffe90 Feb 14 '18 at 16:26

2 Answers2

2

componentWillMount will only run before the first render. It doesn't get run before every render. So even if your state and props update, componentWillMount will not get called again.

The constructor function is the same as well.

You might be looking for componentWillReceiveProps (see docs). This lifecycle event is called when a mounted component is about to receive new props. You can update your state in this lifecycle event.

Note that componentWillReceiveProps only works on mounted components. Therefore, it will not get called the first time your component receives its' initial props.

A side note: Per the docs, you also don't want to introduce any side-effects or subscriptions in componentWillMount. Do that in componentDidMount instead.

Anthony N
  • 973
  • 7
  • 9
0

I would like add a comment, but I don't have enough reputation...

a component will re-render when there has been a change in props

As I understand, you can't change the props, so component re-render on state changes.

AlexanderDSmith
  • 361
  • 3
  • 6
  • Not exactly - if props get changed upstream then the component will update. You are correct in that you can't change the props of a component from itself. It doesn't look like OP makes direct changes to props – Kevin Hoerr Feb 14 '18 at 16:33
  • Thanks for the information @KevinHoerr –  Feb 14 '18 at 16:37