1

A bit of context first, I'm working a questionnaire and decided to start learning React.js. Each step of the questionnaire includes a question and a yes/no radio button group, and also navigation buttons. Here's the jsfiddle. The question component is pretty straight forward, I'm passing the formData and save data function to it in the parent component.

And code for the question component

var Question = React.createClass({
    getInitialState: function() {
        return {
        }
    },
    createMarkup: function(html) {
        return {
            __html: html
        };
    },

    render: function() {
        var subtitle = this.props.subtitle || '';
        var name = this.props.name;
        if (this.props.formData[name] === undefined) {
            var answer_yes = null;
            var answer_no = null;
        } else {
            answer_yes = this.props.formData[name] == "yes" ? true : null;
            answer_no = this.props.formData[name] == "no" ? true : null;
        }
        console.log(answer_yes);
        console.log(answer_no);
        return (
            <div className="container-question">
                <label className="default" dangerouslySetInnerHTML={this.createMarkup(this.props.question)}></label>
                <span className="alert subtitle" dangerouslySetInnerHTML={this.createMarkup(subtitle)}></span>
                <div className="form-group form-group-radio">
                    <div className="row">
                        <div className="col-xs-4">
                            <input type="radio" id={name + "_yes"} name={name} value="yes" defaultChecked={answer_yes} onChange={this.props.saveData}/><label htmlFor="yes">Yes</label><br></br>
                            <input type="radio" id={name + "_no"} name={name} value="no" defaultChecked={answer_no} onChange={this.props.saveData}/><label htmlFor="no">No</label>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
});

The problem is that when you select your answer on the first question and click on next, the radio control on the second question change with it, and same thing happens when you answer second question first. I'm storing the boolean variable for defaultChecked as local variables in the render function and logging them in the console.

Is there any obvious mistake i'm making? any help is appreciated.

0

1 Answer 1

2

Here is an updated jsfiddle that works: https://jsfiddle.net/69z2wepo/8365/

The issue is that you're using what is a called an 'uncontrolled component' in React. See this page for more details: https://facebook.github.io/react/docs/forms.html

Changing to a controlled component for your scenario means using checked instead of defaultChecked. defaultChecked is meant for uncontrolled components where the values of the input controls (in your case radio buttons) are not controlled by the component's props or render method. React is really designed to use controlled components where props/state/render drive exactly what the UI shows.

The first thing you'll notice when changing from using defaultChecked to checked is that you will no longer be able to change the radio state in the UI. The reason this happens is because although the state of your application is being changed in your saveData function, your component is not being re-rendered.

There are a few different approaches to handling this. The updated jsfiddle is re-rendering your application during saveData. Ideally this should be factored differently. Either the saveData should be moved out of the parent component and into a FormDataStore concept (see React Flux architecture, https://facebook.github.io/flux/docs/overview.html) or the parent component should own the formData state and call setState on itself in saveData which will then cause a re-render of that portion of the DOM tree.

Sign up to request clarification or add additional context in comments.

1 Comment

That makes a lot of sense, I've opted to have the parent component own the formData state. Thank you for the explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.