React.js 在渲染子类时意外地重用了 data-reactid

React.js unwantingly reusing data-reactid when rendering subclasses

我有一个 Questionnaire 对象,它呈现多个 QuestionnaireOption 子 classes。当父 Questionnaire 对象中的状态发生变化时,将呈现新的 QuestionnaireOption 子 classes。

QuestionnaireOption class 保持状态,无论是否 "selected"。

问题: 当我更改父 class 中的状态以呈现新的 "Option" 节点时,新节点被分配相同的data-reactid,我希望 Option 节点重置其内部状态,但未为其分配新的 ID,并且它包含错误的状态(在这种情况下,selected 在新的节点上仍设置为 true尽管使用新数据设置了道具)。

如何解决这个问题?

相关代码如下:

QuestionnaireOption = React.createClass({
    getInitialState: function() {
        return {selected: false}
    },
    handleClick: function(e) {
        e.preventDefault();
        this.setState({selected: !this.state.selected});
    },
    render: function() {
        var fullClassName = "questionnaireOption " + (this.state.selected? "selected": "unselected");
        return (
            <div className='questionnaireOptionWrapper large-4 small-4 columns'>
                <div className={fullClassName} onClick={this.handleClick}>
                    <div>{this.props.name}</div>
                </div>
            </div>
        );
    }
});

Questionnaire = React.createClass({
    getInitialState: function() {
        return {currentStage: 0}
    },
    saveOptionState: function() {
        // dump option state into amber.js or localstorage
    },
    advanceWizard: function() {
        this.saveOptionState();
        this.setState({currentStage: this.state.currentStage + 1});
    },
    rewindWizard: function() {
        this.saveOptionState();
        this.setState({currentStage: this.state.currentStage - 1});
    },
    seeResults: function() {
        console.log(globalOptionState);
    },
    render: function() {
        var currentWizardQuestion = wizardQuestions[this.state.currentStage];
        var currentOptionNodes = currentWizardQuestion.options.map(function(option) {
            node = (
                <QuestionnaireOption
                    name={option.name}
                    value={option.value}
                />
            );
            return node;
        });

        return (
            <div className="questionnaire row">
                <div className="questionnaire-question large-8 small-12 columns">
                    <div className="questionnaire-question-text">
                        {currentWizardQuestion.text}
                    </div>
                    <div className="questionnaire-question-subtext">
                        {currentWizardQuestion.subtext}
                    </div>
                    <div className="row">
                        {currentOptionNodes}
                    </div>

                    <input type="button" value="Back" onClick={this.rewindWizard}
                        style={this.state.currentStage == 0? {display: "none"}: {}
                    } />

                    <input type="button" value="Next" onClick={this.advanceWizard}
                        style={this.state.currentStage == wizardQuestions.length - 1?
                            {display: "none"}: {}
                    } />

                    <input type="button" value="Finish" onClick={this.seeResults}
                        style={this.state.currentStage < wizardQuestions.length - 1?
                            {display: "none"}: {}
                    } />
                </div>
            </div>
        );
    }
});

在你的控制台中你有这个警告:

Each child in an array should have a unique "key" prop. Check the render method of App. See fb.me/react-warning-keys for more information.

如果你不这样做,你就没有使用开发版本:你应该修复它。

React 使用两件事来确定渲染之间是否有东西 'the same':组件 class(例如 QuestionnaireOption)和关键道具。

如果两者都不匹配之前的渲染,React 会认为它不同,并重新创建实例* 并丢弃子树dom。

假设 option.name 可用于确定相等性,将您的代码更改为:

    var currentOptionNodes = currentWizardQuestion.options.map(function(option) {
        var node = (
            <QuestionnaireOption
                name={option.name}
                value={option.value}
                key={option.name}
            />
        );
        return node;
    });

作为参考,reactid 是一个实现细节,可能随时更改或删除。

* 如果您只是更改项目的顺序,它会尝试只更改顺序以提高性能。目前有一些情况不会发生这种情况,因此不应依赖它。