1

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
};
3
  • 3
    This is not an answer, but an observation of something that might bite you later. .push doesn't return the array - it returns the count. So I think const list = state.shoes.push(shoe); won't give you what you expect later. Commented Nov 14, 2018 at 13:10
  • Can you show how addShoe is called? Commented Nov 14, 2018 at 13:18
  • I've updated the question. Please let me know if you need anything else Commented Nov 14, 2018 at 13:24

3 Answers 3

2

You can do it this way:

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

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

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

7 Comments

It's called spread
Thanks for you answer, merko. But the result is: Uncaught TypeError: Invalid attempt to spread non-iterable instance. Do I need to install any packages from yarn?
Could you console.log(this.state.shoes), seems like it's not an array or an object ?
Seems that you are correct. The output in chrome is: undefined
Here is the simple app: stackblitz.com/edit/react-2svott Hope it helps, ask anything you need
|
1

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.

Comments

0

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

4 Comments

We don't know how he's calling addShoe yet. He could be doing it with an arrow function or .bind. The addShoe method on the class doesn't necessarily have to be an arrow function.
Doing it with a bind.
Ok now with the update we can say that the way the method is passed is a problem. <ShoeModal onClose={this.addShoe} /> should probably be <ShoeModal onClose={this.addShoe.bind(this)} /> or <ShoeModal onClose={shoe => this.addShoe(shoe)} />
@FrankModica magic! Can you post that as an answer and I'll accept it?

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.