0

This is an oft-searched issue, but I don't seem to be running into the common pitfalls (as far as I can tell).

I have a main component which controls all state. It has a method which is passed in as props to its child component for updating its state that looks like this:

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

Nested beneath this parent component I have another which exists just to loop through and output a list. Looks like this:

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>
        );
    }
}

When changeAttackerAI is called, this console.log runs and my updated data is available.

And finally I have the component that refuses to update. Its render function is never called after the initial render, and componentWillReceiveProps or similar never get called. Looks like this:

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>
        ));
    }
}

What am I doing wrong here?

2
  • can you simplify your code to include only the parts relevant to the problem? Commented Nov 1, 2018 at 1:25
  • Can you highlight which component doesn't update and the desired behaviour? Commented Nov 1, 2018 at 3:29

1 Answer 1

1

Ok I figured out what my issue is. I had a misunderstanding for how the immutability helper functioned. When I did this:

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

I was overwriting my state with a subset of a my state.

What I needed was:

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

I believe the exact issue was that the component was first drawn with the original state, and then I wiped out the original references which caused it to draw. I would think this would cause it to be removed, but apparently not.

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

Comments

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.