Tobias Moe Thorstensen
Tobias Moe Thorstensen

Reputation: 8981

Adding items to an array in javascript

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

Answers (3)

Frank Modica
Frank Modica

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

Nishant Nair
Nishant Nair

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

Merim
Merim

Reputation: 1363

You can do it this way:

this.setState({
     shoes: [...this.state.shoes, newShoe]
})

... adds all elements from this.state.shoes

Upvotes: 2

Related Questions