1

I am relatively new to ReactJs.I am learning react while I am trying to create a real world app. Here is something I cannot solve. I have a repeated component that has one input and one button. everytime the button is clicked, the value of the input will be used in one function.

In Angular I do not have to worry about how to passing those value since in ngFor we can directly assign the value from the ngModel. But there is no such concept in React.

enter image description here

 betOnTeam = (_id, coins) => {
    return;
};

 {this.teamList.map(team => (
    <div key={team._id}>
       <input type="number" min="100" max="5000"  />
       <button type="button"
               onClick={() => this.betOnTeam(team._id,//value from the 
   input above)}> 
    </div>
  ))}

So basically I Have a function ready to receive an Id and how many coins the user bet. And As we can see from the picture, I have many inputs which should contain the value of how much coins the user put for a specific team. each button will trigger this betOnTeam function and will pass the unique Id of the team, and the number coins the user bet. How can I set states for all thoese teams since they are all dynamic, it could be 5 teams or 100 teams. Is it any way to do it dynamically?

e.g. user input 5000, when he click the button, the id and the value will be passed into the function betOnTeam.

I hope this clarified my question.

================================== Thanks for all the input from you guys.

I have make it working combine with all your suggestions.

So Here is what I do:

 betOnTeam = (event, id) => {
    console.log(event.target[0].value, id);
    return;
};

 {this.teamList.map(team => (
    <form key={team._id} onSubmit={(e) => this.betOnTeam(e,team._id)}>
       <input type="number" min="100" max="5000"  />
       <button type="submit"> 
    </form >
  ))}
3
  • 1
    Firstly, you need to understand the basic of using <input/> in react way. Please checkout controlled and uncontrolled component. reactjs.org/docs/uncontrolled-components.html and reactjs.org/docs/forms.html#controlled-components. Commented Jul 9, 2019 at 3:21
  • Thanks the uncontrolled component really helps me. Commented Jul 9, 2019 at 3:54
  • @JohnathanLi try my solution below, I think it will give you a better insight on how to use React more effectively. Commented Jul 9, 2019 at 4:11

3 Answers 3

2

Seems like you're really close. I think this ultimately comes down to how you want to construct your components. There is an easy way to do this (the more React) way, and there is a hard way.

The easy way is to split the mark-up created inside the .map() into its own component. You will have an individual component for each team, thus the state is encapsulated to its own component. By doing this you can effectively keep track of the inputs for each team.

Consider this sandbox for example: https://codesandbox.io/s/dazzling-roentgen-jp8zm

We can create a component for the markup like this:

Team

import React from "react"

class Team extends React.Component {
  state = {
    betValue: 100
  };

  handleOnChange = e => {
    this.setState({
      betValue: e.target.value
    });
  };

  handleOnClick = () => {
    this.props.betOnTeam(this.state.betValue, this.props.id);
  };

  render() {
    const { id } = this.props;
    const { betValue } = this.state;
    return (
      <div key={id}>
        <input
          type="number"
          min="100"
          max="5000"
          value={betValue}
          onChange={this.handleOnChange}
        />
        <button onClick={this.handleOnClick} type="button">
          Bet
        </button>
      </div>
    );
  }
}

export default Team;

So from a purely jsx standpoint, the markup is the same, but now it is contained inside a class-component.

  • Now we can keep track of the inputs in a controlled manner. When we're ready to place the bet, the value is stored in the individual component state.
  • We pass down two properties to each Team component, the team_id and betOnTeam function. The team_id can be accessed using this.props.id and likewise we will pass it into this.props.betOnTeam() when required.

Main Component

import React from "react"
import Team from "./Team"

class App extends React.Component {
  teamList = [
    { team_id: 1, name: "TSM" },
    { team_id: 2, name: "SKT" },
    { team_id: 3, name: "CLG" }
  ];

  betOnTeam = (betValue, teamId) => {
    console.log(betValue);
    console.log(teamId);
  };

  render() {
    return (
      <div>
        {this.teamList.map(team => (
          <Team id={team.team_id} betOnTeam={this.betOnTeam} />
        ))}
      </div>
    );
  }
}

So the .map() renders a Team component for each team and passes in their respective ids and the betOnTeam function as props. When the button inside the component is clicked, we can pass back up the values stored in the Team Component to execute betOnTeam.

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

2 Comments

Yes, You are so correct. I am so stucked with angular way. Thanks for this informative answer. I should use component or stateless component to passing those value since they has their own state/props. How can I missed that XD.
LOL you're welcome friend. And no worries, I have the exact same problem when I use Angular. I'm always thinking about react-state and never think about ng methods haha. @JohnathanLi
0

onClick={this.betOnTeam(form._id,value)}

Don't execute this.betOnTeam right from the start, you're actually setting the click handler to the returned result of this.betOnTeam(form._id,value). In React, it's not quite the same as in Angular. For this, you need to set it equal to a function that does that. Like this:

onClick={() => this.betOnTeam(form._id,value)}

Hope this helps.

1 Comment

Hi Thanks for the fast reply. I have updated my question whcih I think it clarified it better.
0
1. this.betOnTeam = (_id, value) => { ... }

2. constructor(props) { this.betOnTeam.bind(this) }

3. onClick = { () => this.betOnTeam(form._id, value)}

Well if you use onClick = { this.betOnTeam(form._id, value) }, then the code will be executed first, and in betOnTeam function, you will not use 'this' operator.

But if you use the above methods, then you can use 'this' in the function and get the good results.

And your code has some bugs to fix,

{this.array.map(form => (
    <div key={form._id}>
       <input name={`editform{form._id}`} type="number" min="100" max="5000" onChange={(e) => this.changeNumber(e, form._id) }/>
       <button type="button"
               onClick={this.betOnTeam(form._id,value)}> 
    </div>
))}

And in changeNumber function, you should use setState({}) function to set the value to the state, and in betOnTeam function, you can use the state you have already set.

The code must be like this, or otherwise you can use ref but it is not formally encouraged to use ref. Totally, you should use ControlledComponent. That's the target.

I hope you to solve the problem.

1 Comment

Hi Thanks for the fast reply. I have updated my question whcih I think it clarified it better.

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.