反应嵌套组件不随道具变化而更新?

时间:2018-11-01 01:04:03

标签: reactjs

这是一个经常搜索的问题,但据我所知,我似乎并没有遇到常见的陷阱。

我有一个控制所有状态的主要部件。它有一个方法作为道具传入其子组件以更新其状态,如下所示:

changeAttackerAI = (target, index) => {
    this.setState(update(this.state.attackers,
        {
            [index]: {$set: {'ai': {[target.name]: target.value}}},
        }
    ))
}

在这个父组件下面有一个嵌套的组件,它存在另一个只是为了循环并输出列表。看起来像这样:

class Attackers extends Component {
    render() {
        return (
            <div className="attackers">
                {this.props.models.map((model, index) => {
                    console.log(model)
                    return <Attacker key={index}
                                index={index}
                                modelData={model}
                                removeAttacker={this.props.removeAttacker}
                                reorderAttackers={this.props.reorderAttackers}
                                changeAttackerAI={this.props.changeAttackerAI}
                            />
                })}
            </div>
        );
    }
}

调用changeAttackerAI时,此console.log运行,并且我的更新数据可用。

最后,我有了拒绝更新的组件。最初的渲染之后再也不会调用它的渲染函数,也不会调用componentWillReceiveProps或类似函数。看起来像这样:

class Attacker extends Component {

    removeAttacker = () => {
        this.props.removeAttacker(this.props.index)
    }

    changeAttackerAI = (e) => {
        this.props.changeAttackerAI(e.target, this.props.index)
    }

    radioButtonOption = (name, value, label) => {
        const existingValue = _.get(this.props.modelData, 'ai.' + name, null)
        return <label><input type="radio" name={name} checked={existingValue === value} value={value} onChange={this.changeAttackerAI} /> {label}</label>
    }

    render() {
        const {isDragging, connectDragSource, connectDropTarget, modelData} = this.props

        console.log(modelData)

        const opacity = isDragging ? 0 : 1

        return connectDragSource(connectDropTarget(
            <div className="attacker" style={{'opacity': opacity}}>
                {modelData.modelName}
                <button onClick={this.removeAttacker}>x</button>
                <div className="boost_hit">
                    <h3>Boost Hit</h3>
                    {this.radioButtonOption('boost_hit', 'none', 'None')}
                    {this.radioButtonOption('boost_hit', 'all', 'All')}
                    {this.radioButtonOption('boost_hit', 'initials', 'Initials')}
                    {this.radioButtonOption('boost_hit', 'chain_attack', 'Chain Attack')}
                    <label><input type="checkbox" name="free_hit_boosts" value="1" onChange={this.changeAttackerAI} /> Free boosts?</label>
                </div>
                <div className="boost_damage">
                    <h3>Boost Damage</h3>
                    {this.radioButtonOption('boost_damage', 'none', 'None')}
                    {this.radioButtonOption('boost_damage', 'all', 'All')}
                    {this.radioButtonOption('boost_damage', 'initials', 'Initials')}
                    {this.radioButtonOption('boost_damage', 'chain_attack', 'Chain Attack')}
                    <label><input type="checkbox" name="free_damage_boosts" value="1" onChange={this.changeAttackerAI} /> Free boosts?</label>
                </div>
            </div>
        ));
    }
}

我在这里做错了什么?

1 个答案:

答案 0 :(得分:0)

好的,我知道了我的问题所在。我对不变性助手的功能有误解。当我这样做时:

this.setState(update(this.state.attackers,
    {
        [index]: {$set: {'ai': {[target.name]: target.value}}},
    }
))

我正在用状态的子集覆盖状态。

我需要的是:

    this.setState(update(this.state,
        {
            attackers: {
                [index]: {'ai': {$merge: {[target.name]: target.value}}},
            }
        }
    ))

我认为确切的问题是该组件首先以原始状态绘制,然后擦除了导致其绘制的原始引用。我认为这会导致将其删除,但显然不会删除。