Reputation: 8981
Admit it. Being new to JavaScript in 2018 is difficult. Coming from languages like C#, Java and Typescript(yeah subset of js..) where type safety is key, Javascript just keep f***** me over. I struggle with something simple like updating an array..
So I have this React
component, where the state is defined like this:
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
show: false,
shoes: []
};
}
....
...
}
The shoes is an array of undefined(?)
This array is passed to a stateless component which looks like this
const Shoelist = props => {
return (
<Wrapper>
{props.shoes.map((shoe, i) => (
<div key={i}>
<Shoe shoe={shoe} />
<Separator />
</div>
))}
</Wrapper>
);
};
I in my Form
component, I have a method which is supposed to react(doh) on onClick
methods. In this method I get a parameter with a new shoe to add in this list. This is very it stops for me in javascript - something which is faaaaairly easy in all other languages that we've being using for the past years..
I've tried several ways:
1#
addShoe(shoe) {
this.setState(state => {
const list = state.shoes.push(shoe);
return {
list
};
});
}
This results in an error: Uncaught TypeError: Cannot read property 'push' of undefined
Do I need to define shoes as an Array
? I thought the []
was enough
2#
I googled, I do that alot. I found one blog post saying something about react-addons-update
. I installed this by running yarn add
and code looks like this:
addShoe(shoe) {
this.setState(update(this.state, { shoes: { $push: [shoe] } }));
}
which results in Uncaught Error: update(): expected target of $push to be an array; got undefined.
Help! How difficult can this be?
EDIT
I pass this method into another component like this:
<ShoeModal onClose={this.addShoe} />
in the ShoeModal component this is bound to a onClick method:
<FinishModalButton
onClick={this.props.onClose.bind(this, this.state.shoe)}>
....
</FinishModalButton>
ShoeModal.propTypes = {
onClose: PropTypes.func.isRequired
};
Upvotes: 1
Views: 182
Reputation: 10536
With your updates we can see that the issue is the way the addShoe
callback is passed. It's being invoked as a function instead of a method of an object, so it loses context.
Change it to:
<ShoeModal onClose={this.addShoe.bind(this)} />
or
<ShoeModal onClose={shoe => this.addShoe(shoe)} />
In addition, .push
returns the count of the array, so the following line won't give you what you expect:
const list = state.shoes.push(shoe);
See @merko's answer for a solution.
Upvotes: 1
Reputation: 2020
Firstly, your addShoe
method is not an arrow function.
Using arrow functions because the context this
is of the component.
Second, you are returning the object {list}
. This sets the variable list
in state.
Also push to the new list
variable instead of mutating state.
Change your function to
addShoe = (shoe) => {
this.setState(state => {
let list = state.shoes;
list.push(shoe);
return {
shoes : list
};
});
}
Upvotes: 0
Reputation: 1363
You can do it this way:
this.setState({
shoes: [...this.state.shoes, newShoe]
})
...
adds all elements from this.state.shoes
Upvotes: 2