react counter for each item of list











up vote
1
down vote

favorite












I'm trying to create a counter for each item in a list in React. I want each to be incremented or decremented individually depending on what the user clicks on. This issue is that all counters increment and decrement on click
of a single element, but I would like only the clicked element's counter to change.



this is my code:



class name extends Component {

constructor(){
super()

this.state = {
news: ,
voteing: 0
}
}

onVoting(type){
this.setState(prevState => {
return {voteing: type == 'add' ? prevState.voteing + 1: prevState.voteing- 1}
});
}

render() {
return (
<React.Fragment>
<Content>
{
this.state.news.map((item, i)=>{
return (
<Item key={i}>
<text>
{item.subject}
{item.details}
</text>
<Votering>
<img src="" onClick={this.onVoting.bind(this, 'add')} />
<div value={this.state.voteing}>{this.state.voteing}</div>
<img src="" onClick={this.onVoting.bind(this, 'min')} />
</Votering>
</Item>
)
})
}
</Content>
</React.Fragment>
)
}
}


I'm trying to do this:



<img src="" onClick={this.onVote(i).bind(this, 'add')} />


but it doesn't work also tried this.onVote(item.i) and same result










share|improve this question
























  • could I get a sample of what the news array looks like?
    – joshua fermin
    Nov 19 at 23:06










  • I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
    – GNDevs
    Nov 19 at 23:08










  • The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
    – AnonymousSB
    Nov 19 at 23:18

















up vote
1
down vote

favorite












I'm trying to create a counter for each item in a list in React. I want each to be incremented or decremented individually depending on what the user clicks on. This issue is that all counters increment and decrement on click
of a single element, but I would like only the clicked element's counter to change.



this is my code:



class name extends Component {

constructor(){
super()

this.state = {
news: ,
voteing: 0
}
}

onVoting(type){
this.setState(prevState => {
return {voteing: type == 'add' ? prevState.voteing + 1: prevState.voteing- 1}
});
}

render() {
return (
<React.Fragment>
<Content>
{
this.state.news.map((item, i)=>{
return (
<Item key={i}>
<text>
{item.subject}
{item.details}
</text>
<Votering>
<img src="" onClick={this.onVoting.bind(this, 'add')} />
<div value={this.state.voteing}>{this.state.voteing}</div>
<img src="" onClick={this.onVoting.bind(this, 'min')} />
</Votering>
</Item>
)
})
}
</Content>
</React.Fragment>
)
}
}


I'm trying to do this:



<img src="" onClick={this.onVote(i).bind(this, 'add')} />


but it doesn't work also tried this.onVote(item.i) and same result










share|improve this question
























  • could I get a sample of what the news array looks like?
    – joshua fermin
    Nov 19 at 23:06










  • I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
    – GNDevs
    Nov 19 at 23:08










  • The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
    – AnonymousSB
    Nov 19 at 23:18















up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm trying to create a counter for each item in a list in React. I want each to be incremented or decremented individually depending on what the user clicks on. This issue is that all counters increment and decrement on click
of a single element, but I would like only the clicked element's counter to change.



this is my code:



class name extends Component {

constructor(){
super()

this.state = {
news: ,
voteing: 0
}
}

onVoting(type){
this.setState(prevState => {
return {voteing: type == 'add' ? prevState.voteing + 1: prevState.voteing- 1}
});
}

render() {
return (
<React.Fragment>
<Content>
{
this.state.news.map((item, i)=>{
return (
<Item key={i}>
<text>
{item.subject}
{item.details}
</text>
<Votering>
<img src="" onClick={this.onVoting.bind(this, 'add')} />
<div value={this.state.voteing}>{this.state.voteing}</div>
<img src="" onClick={this.onVoting.bind(this, 'min')} />
</Votering>
</Item>
)
})
}
</Content>
</React.Fragment>
)
}
}


I'm trying to do this:



<img src="" onClick={this.onVote(i).bind(this, 'add')} />


but it doesn't work also tried this.onVote(item.i) and same result










share|improve this question















I'm trying to create a counter for each item in a list in React. I want each to be incremented or decremented individually depending on what the user clicks on. This issue is that all counters increment and decrement on click
of a single element, but I would like only the clicked element's counter to change.



this is my code:



class name extends Component {

constructor(){
super()

this.state = {
news: ,
voteing: 0
}
}

onVoting(type){
this.setState(prevState => {
return {voteing: type == 'add' ? prevState.voteing + 1: prevState.voteing- 1}
});
}

render() {
return (
<React.Fragment>
<Content>
{
this.state.news.map((item, i)=>{
return (
<Item key={i}>
<text>
{item.subject}
{item.details}
</text>
<Votering>
<img src="" onClick={this.onVoting.bind(this, 'add')} />
<div value={this.state.voteing}>{this.state.voteing}</div>
<img src="" onClick={this.onVoting.bind(this, 'min')} />
</Votering>
</Item>
)
})
}
</Content>
</React.Fragment>
)
}
}


I'm trying to do this:



<img src="" onClick={this.onVote(i).bind(this, 'add')} />


but it doesn't work also tried this.onVote(item.i) and same result







reactjs






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 at 23:11

























asked Nov 19 at 23:00









GNDevs

15310




15310












  • could I get a sample of what the news array looks like?
    – joshua fermin
    Nov 19 at 23:06










  • I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
    – GNDevs
    Nov 19 at 23:08










  • The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
    – AnonymousSB
    Nov 19 at 23:18




















  • could I get a sample of what the news array looks like?
    – joshua fermin
    Nov 19 at 23:06










  • I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
    – GNDevs
    Nov 19 at 23:08










  • The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
    – AnonymousSB
    Nov 19 at 23:18


















could I get a sample of what the news array looks like?
– joshua fermin
Nov 19 at 23:06




could I get a sample of what the news array looks like?
– joshua fermin
Nov 19 at 23:06












I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
– GNDevs
Nov 19 at 23:08




I'm fetch data from api so is the link of this api will be enough for you? @joshua fermin
– GNDevs
Nov 19 at 23:08












The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
– AnonymousSB
Nov 19 at 23:18






The issue is that voteing is the only thing you're tracking, a single value in the state, that you're sharing between all iterations of your map. Also, it's just "voting", no e
– AnonymousSB
Nov 19 at 23:18














3 Answers
3






active

oldest

votes

















up vote
1
down vote



accepted










The reason all your items' counts change when any of them is clicked on is that they all share the same vote count value, voteing in the name component's state.



To fix this, you should break each item into its own stateful component. So that each can track its own click count.



For example:



class name extends Component {
constructor(){
super();
this.state = {
news:
}
}

render() {
return (
<React.Fragment>
<Content>
{
this.state.news.map((item, i) => {
return <NewsItem key={ i }
subject={ item.subject }
details={ item.details }
/>
})
}
</Content>
</React.Fragment>
)
}
}

class NewsItem extends Component {
constructor() {
super();
this.state = {
voteCount = 0
}
}

handleVote(type) {
this.setState(prevState => ({
voteCount: type === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
}));
}

render() {
const { subject, details } = this.props;
const { voteCount } = this.state;

return (
<Item>
<text>
{ subject }
{ details }
</text>
<Votering>
<img src="" onClick={ this.handleVote.bind(this, 'add') } />
<div value={ voteCount }>{ voteCount }</div>
<img src="" onClick={ this.handleVote.bind(this, 'min') } />
</Votering>
</Item>
)
}
}


You could also maintain separate counts for each item within the parent component, but I find breaking into separate components to be much cleaner.






share|improve this answer





















  • one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
    – Icepickle
    Nov 19 at 23:23










  • okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
    – GNDevs
    Nov 19 at 23:30






  • 1




    @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
    – Henry Woody
    Nov 19 at 23:36




















up vote
2
down vote













I cannot really see how you would like to see voting as part of the local component state, as it really has to do (in my opinion), with the entities on which you can vote.



So if I were you, I would rewrite the code slightly different. As I do not know what you intend to do afterwards with the votes (this rather assumes like a live process, or at least a kind of save button, as it is saved here in the local VotingApp state), I just save everything to the local state, how you would handle that is not really my intend to answer.



So personally, I would rather go for one functional component, just rendering the news item and it's voting capability, where the voteCount is part of the item entity. If this is not how you receive the data, nothing stops you from adding the data after your fetch and before really showing it on the screen. The app itself will receive the changes and the item that will be changed, and what it does there-after, would be all up to you ;)






const { Component } = React;

const NewsItem = ( item ) => {
const { subject, details, voteCount, handleVoteChange } = item;
return (
<div className="news-item">
<div className="news-vote">
<div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
<div className="vote-count">{ voteCount }</div>
<div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
</div>
<div className="news-content">
<h3>{ subject }</h3>
<div>{ details }</div>
</div>
</div>
);
};

class VotingApp extends Component {
constructor( props ) {
super();
this.handleVoteChange = this.handleVoteChange.bind( this );
// by lack of fetching I add the initial newsItems to the state
// and work by updating local state on voteChanges
// depending on your state management (I guess you want to do something with the votes)
// you could change this
this.state = {
newsItems: props.newsItems
};
}
handleVoteChange( item, increment ) {
this.setState( ( prevState ) => {
const { newsItems } = prevState;
// updates only the single item that has changed
return {
newsItems: newsItems
.map( oldItem => oldItem.id === item.id ?
{ ...oldItem, voteCount: oldItem.voteCount + increment } :
oldItem ) };
} );
}
render() {
const { newsItems = } = this.state;
return (
<div className="kiosk">
{ newsItems.map( item => <NewsItem
key={ item.id }
{...item}
handleVoteChange={this.handleVoteChange} /> ) }
</div>
);
}
}

// some bogus news items
const newsItems = [
{ id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
{ id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
{ id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
];

// render towards the container
const target = document.querySelector('#container');
ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

.kiosk {
display: flex;
flex-wrap: no-wrap;
}
.news-item {
display: flex;
justify-content: flex-start;
width: 100%;
}
.news-vote {
display: flex;
flex-direction: column;
align-items: center;
padding-left: 10px;
padding-right: 10px;
}
.news-vote > * {
cursor: pointer;
}
.news-content {
display: flex;
flex-direction: column;
}
.vote-up::before {
content: '▲';
}
.vote-down::before {
content: '▼';
}
.vote-up:hover, .vote-down:hover {
color: #cfcfcf;
}
h3 { margin: 0; }

<script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
<script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
<script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
<script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
<div id="container"></div>








share|improve this answer




























    up vote
    1
    down vote













    A few things I noticed unrelated to your question.



    1) onVoting should be bound in your constructor or use onVoting = () => { ..... }



    2) in your render function you have onVote instead of onVoting



    On to your main question, in your state you are only maintaining one counter that is displayed and changed for all news elements. an easy way to get around this is to create a new react element for each news article that will handle the voting for each article.



    class parent extends Component {

    constructor(){
    super()

    this.state = {
    news: null,
    }
    }
    componentDidMount() {
    // fetch data from api and minipulate as needed
    this.setState({news: dataFromApi})
    }

    render() {
    return (
    <Content>
    {
    this.state.news.map((item, i)=>{
    return (
    <NewChildComponent data={item}/>
    )
    })
    }
    </Content>
    )
    }
    }

    class NewChildComponent extends Component {
    constructor() {
    super()
    this.state = {
    voting: 0,
    }
    }
    onVoting = (e) => {
    this.setState(prevState => ({
    voteCount: e.target.name === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
    }));
    }
    render () {
    const {data} = this.props;
    return (
    <Item key={data.uniqueID}>
    <text>
    {data.subject}
    {data.details}
    </text>
    <Votering>
    <img src="" onClick={this.onVoting} name="add"/>
    <div value={this.state.voteing}>{this.state.voteing}</div>
    <img src="" onClick={this.onVoting} name="min"/>
    </Votering>
    </Item>
    )
    }
    }


    A little background on why you should not bind in your render function. https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36




    Here’s why: The parent component is passing down an arrow function on
    props. Arrow functions are reallocated on every render (same story
    with using bind). So although I’ve declared User.js as a
    PureComponent, the arrow function in User’s parent causes the User
    component to see a new function being sent in on props for all users.
    So every user re-renders when any delete button is clicked. 👎




    Also why you should not use an index as a key in React.
    https://reactjs.org/docs/lists-and-keys.html




    We don’t recommend using indexes for keys if the order of items may
    change. This can negatively impact performance and may cause issues
    with component state. Check out Robin Pokorny’s article for an
    in-depth explanation on the negative impacts of using an index as a
    key. If you choose not to assign an explicit key to list items then
    React will default to using indexes as keys.



    Here is an in-depth explanation about why keys are necessary if you’re
    interested in learning more.







    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383864%2freact-counter-for-each-item-of-list%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      1
      down vote



      accepted










      The reason all your items' counts change when any of them is clicked on is that they all share the same vote count value, voteing in the name component's state.



      To fix this, you should break each item into its own stateful component. So that each can track its own click count.



      For example:



      class name extends Component {
      constructor(){
      super();
      this.state = {
      news:
      }
      }

      render() {
      return (
      <React.Fragment>
      <Content>
      {
      this.state.news.map((item, i) => {
      return <NewsItem key={ i }
      subject={ item.subject }
      details={ item.details }
      />
      })
      }
      </Content>
      </React.Fragment>
      )
      }
      }

      class NewsItem extends Component {
      constructor() {
      super();
      this.state = {
      voteCount = 0
      }
      }

      handleVote(type) {
      this.setState(prevState => ({
      voteCount: type === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
      }));
      }

      render() {
      const { subject, details } = this.props;
      const { voteCount } = this.state;

      return (
      <Item>
      <text>
      { subject }
      { details }
      </text>
      <Votering>
      <img src="" onClick={ this.handleVote.bind(this, 'add') } />
      <div value={ voteCount }>{ voteCount }</div>
      <img src="" onClick={ this.handleVote.bind(this, 'min') } />
      </Votering>
      </Item>
      )
      }
      }


      You could also maintain separate counts for each item within the parent component, but I find breaking into separate components to be much cleaner.






      share|improve this answer





















      • one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
        – Icepickle
        Nov 19 at 23:23










      • okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
        – GNDevs
        Nov 19 at 23:30






      • 1




        @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
        – Henry Woody
        Nov 19 at 23:36

















      up vote
      1
      down vote



      accepted










      The reason all your items' counts change when any of them is clicked on is that they all share the same vote count value, voteing in the name component's state.



      To fix this, you should break each item into its own stateful component. So that each can track its own click count.



      For example:



      class name extends Component {
      constructor(){
      super();
      this.state = {
      news:
      }
      }

      render() {
      return (
      <React.Fragment>
      <Content>
      {
      this.state.news.map((item, i) => {
      return <NewsItem key={ i }
      subject={ item.subject }
      details={ item.details }
      />
      })
      }
      </Content>
      </React.Fragment>
      )
      }
      }

      class NewsItem extends Component {
      constructor() {
      super();
      this.state = {
      voteCount = 0
      }
      }

      handleVote(type) {
      this.setState(prevState => ({
      voteCount: type === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
      }));
      }

      render() {
      const { subject, details } = this.props;
      const { voteCount } = this.state;

      return (
      <Item>
      <text>
      { subject }
      { details }
      </text>
      <Votering>
      <img src="" onClick={ this.handleVote.bind(this, 'add') } />
      <div value={ voteCount }>{ voteCount }</div>
      <img src="" onClick={ this.handleVote.bind(this, 'min') } />
      </Votering>
      </Item>
      )
      }
      }


      You could also maintain separate counts for each item within the parent component, but I find breaking into separate components to be much cleaner.






      share|improve this answer





















      • one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
        – Icepickle
        Nov 19 at 23:23










      • okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
        – GNDevs
        Nov 19 at 23:30






      • 1




        @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
        – Henry Woody
        Nov 19 at 23:36















      up vote
      1
      down vote



      accepted







      up vote
      1
      down vote



      accepted






      The reason all your items' counts change when any of them is clicked on is that they all share the same vote count value, voteing in the name component's state.



      To fix this, you should break each item into its own stateful component. So that each can track its own click count.



      For example:



      class name extends Component {
      constructor(){
      super();
      this.state = {
      news:
      }
      }

      render() {
      return (
      <React.Fragment>
      <Content>
      {
      this.state.news.map((item, i) => {
      return <NewsItem key={ i }
      subject={ item.subject }
      details={ item.details }
      />
      })
      }
      </Content>
      </React.Fragment>
      )
      }
      }

      class NewsItem extends Component {
      constructor() {
      super();
      this.state = {
      voteCount = 0
      }
      }

      handleVote(type) {
      this.setState(prevState => ({
      voteCount: type === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
      }));
      }

      render() {
      const { subject, details } = this.props;
      const { voteCount } = this.state;

      return (
      <Item>
      <text>
      { subject }
      { details }
      </text>
      <Votering>
      <img src="" onClick={ this.handleVote.bind(this, 'add') } />
      <div value={ voteCount }>{ voteCount }</div>
      <img src="" onClick={ this.handleVote.bind(this, 'min') } />
      </Votering>
      </Item>
      )
      }
      }


      You could also maintain separate counts for each item within the parent component, but I find breaking into separate components to be much cleaner.






      share|improve this answer












      The reason all your items' counts change when any of them is clicked on is that they all share the same vote count value, voteing in the name component's state.



      To fix this, you should break each item into its own stateful component. So that each can track its own click count.



      For example:



      class name extends Component {
      constructor(){
      super();
      this.state = {
      news:
      }
      }

      render() {
      return (
      <React.Fragment>
      <Content>
      {
      this.state.news.map((item, i) => {
      return <NewsItem key={ i }
      subject={ item.subject }
      details={ item.details }
      />
      })
      }
      </Content>
      </React.Fragment>
      )
      }
      }

      class NewsItem extends Component {
      constructor() {
      super();
      this.state = {
      voteCount = 0
      }
      }

      handleVote(type) {
      this.setState(prevState => ({
      voteCount: type === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
      }));
      }

      render() {
      const { subject, details } = this.props;
      const { voteCount } = this.state;

      return (
      <Item>
      <text>
      { subject }
      { details }
      </text>
      <Votering>
      <img src="" onClick={ this.handleVote.bind(this, 'add') } />
      <div value={ voteCount }>{ voteCount }</div>
      <img src="" onClick={ this.handleVote.bind(this, 'min') } />
      </Votering>
      </Item>
      )
      }
      }


      You could also maintain separate counts for each item within the parent component, but I find breaking into separate components to be much cleaner.







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Nov 19 at 23:20









      Henry Woody

      3,4562824




      3,4562824












      • one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
        – Icepickle
        Nov 19 at 23:23










      • okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
        – GNDevs
        Nov 19 at 23:30






      • 1




        @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
        – Henry Woody
        Nov 19 at 23:36




















      • one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
        – Icepickle
        Nov 19 at 23:23










      • okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
        – GNDevs
        Nov 19 at 23:30






      • 1




        @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
        – Henry Woody
        Nov 19 at 23:36


















      one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
      – Icepickle
      Nov 19 at 23:23




      one would wonder if it should be component state, or simply part of the entity, but okay that much info is not really available :)
      – Icepickle
      Nov 19 at 23:23












      okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
      – GNDevs
      Nov 19 at 23:30




      okay I understand the issue now but I couldn't understand how can keep separates counts within the name component can you give me an example please @Henry Woody
      – GNDevs
      Nov 19 at 23:30




      1




      1




      @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
      – Henry Woody
      Nov 19 at 23:36






      @GNDevs I would really recommend against doing it that way because it's messy and easy to get bugs. But if you really want to, you'll have to change this.state.voteing to an array of vote counts that correspond to the news items by index. Then on click, update count at the correct index.
      – Henry Woody
      Nov 19 at 23:36














      up vote
      2
      down vote













      I cannot really see how you would like to see voting as part of the local component state, as it really has to do (in my opinion), with the entities on which you can vote.



      So if I were you, I would rewrite the code slightly different. As I do not know what you intend to do afterwards with the votes (this rather assumes like a live process, or at least a kind of save button, as it is saved here in the local VotingApp state), I just save everything to the local state, how you would handle that is not really my intend to answer.



      So personally, I would rather go for one functional component, just rendering the news item and it's voting capability, where the voteCount is part of the item entity. If this is not how you receive the data, nothing stops you from adding the data after your fetch and before really showing it on the screen. The app itself will receive the changes and the item that will be changed, and what it does there-after, would be all up to you ;)






      const { Component } = React;

      const NewsItem = ( item ) => {
      const { subject, details, voteCount, handleVoteChange } = item;
      return (
      <div className="news-item">
      <div className="news-vote">
      <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
      <div className="vote-count">{ voteCount }</div>
      <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
      </div>
      <div className="news-content">
      <h3>{ subject }</h3>
      <div>{ details }</div>
      </div>
      </div>
      );
      };

      class VotingApp extends Component {
      constructor( props ) {
      super();
      this.handleVoteChange = this.handleVoteChange.bind( this );
      // by lack of fetching I add the initial newsItems to the state
      // and work by updating local state on voteChanges
      // depending on your state management (I guess you want to do something with the votes)
      // you could change this
      this.state = {
      newsItems: props.newsItems
      };
      }
      handleVoteChange( item, increment ) {
      this.setState( ( prevState ) => {
      const { newsItems } = prevState;
      // updates only the single item that has changed
      return {
      newsItems: newsItems
      .map( oldItem => oldItem.id === item.id ?
      { ...oldItem, voteCount: oldItem.voteCount + increment } :
      oldItem ) };
      } );
      }
      render() {
      const { newsItems = } = this.state;
      return (
      <div className="kiosk">
      { newsItems.map( item => <NewsItem
      key={ item.id }
      {...item}
      handleVoteChange={this.handleVoteChange} /> ) }
      </div>
      );
      }
      }

      // some bogus news items
      const newsItems = [
      { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
      { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
      { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
      ];

      // render towards the container
      const target = document.querySelector('#container');
      ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

      .kiosk {
      display: flex;
      flex-wrap: no-wrap;
      }
      .news-item {
      display: flex;
      justify-content: flex-start;
      width: 100%;
      }
      .news-vote {
      display: flex;
      flex-direction: column;
      align-items: center;
      padding-left: 10px;
      padding-right: 10px;
      }
      .news-vote > * {
      cursor: pointer;
      }
      .news-content {
      display: flex;
      flex-direction: column;
      }
      .vote-up::before {
      content: '▲';
      }
      .vote-down::before {
      content: '▼';
      }
      .vote-up:hover, .vote-down:hover {
      color: #cfcfcf;
      }
      h3 { margin: 0; }

      <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
      <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
      <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
      <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
      <div id="container"></div>








      share|improve this answer

























        up vote
        2
        down vote













        I cannot really see how you would like to see voting as part of the local component state, as it really has to do (in my opinion), with the entities on which you can vote.



        So if I were you, I would rewrite the code slightly different. As I do not know what you intend to do afterwards with the votes (this rather assumes like a live process, or at least a kind of save button, as it is saved here in the local VotingApp state), I just save everything to the local state, how you would handle that is not really my intend to answer.



        So personally, I would rather go for one functional component, just rendering the news item and it's voting capability, where the voteCount is part of the item entity. If this is not how you receive the data, nothing stops you from adding the data after your fetch and before really showing it on the screen. The app itself will receive the changes and the item that will be changed, and what it does there-after, would be all up to you ;)






        const { Component } = React;

        const NewsItem = ( item ) => {
        const { subject, details, voteCount, handleVoteChange } = item;
        return (
        <div className="news-item">
        <div className="news-vote">
        <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
        <div className="vote-count">{ voteCount }</div>
        <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
        </div>
        <div className="news-content">
        <h3>{ subject }</h3>
        <div>{ details }</div>
        </div>
        </div>
        );
        };

        class VotingApp extends Component {
        constructor( props ) {
        super();
        this.handleVoteChange = this.handleVoteChange.bind( this );
        // by lack of fetching I add the initial newsItems to the state
        // and work by updating local state on voteChanges
        // depending on your state management (I guess you want to do something with the votes)
        // you could change this
        this.state = {
        newsItems: props.newsItems
        };
        }
        handleVoteChange( item, increment ) {
        this.setState( ( prevState ) => {
        const { newsItems } = prevState;
        // updates only the single item that has changed
        return {
        newsItems: newsItems
        .map( oldItem => oldItem.id === item.id ?
        { ...oldItem, voteCount: oldItem.voteCount + increment } :
        oldItem ) };
        } );
        }
        render() {
        const { newsItems = } = this.state;
        return (
        <div className="kiosk">
        { newsItems.map( item => <NewsItem
        key={ item.id }
        {...item}
        handleVoteChange={this.handleVoteChange} /> ) }
        </div>
        );
        }
        }

        // some bogus news items
        const newsItems = [
        { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
        { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
        { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
        ];

        // render towards the container
        const target = document.querySelector('#container');
        ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

        .kiosk {
        display: flex;
        flex-wrap: no-wrap;
        }
        .news-item {
        display: flex;
        justify-content: flex-start;
        width: 100%;
        }
        .news-vote {
        display: flex;
        flex-direction: column;
        align-items: center;
        padding-left: 10px;
        padding-right: 10px;
        }
        .news-vote > * {
        cursor: pointer;
        }
        .news-content {
        display: flex;
        flex-direction: column;
        }
        .vote-up::before {
        content: '▲';
        }
        .vote-down::before {
        content: '▼';
        }
        .vote-up:hover, .vote-down:hover {
        color: #cfcfcf;
        }
        h3 { margin: 0; }

        <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
        <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
        <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
        <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
        <div id="container"></div>








        share|improve this answer























          up vote
          2
          down vote










          up vote
          2
          down vote









          I cannot really see how you would like to see voting as part of the local component state, as it really has to do (in my opinion), with the entities on which you can vote.



          So if I were you, I would rewrite the code slightly different. As I do not know what you intend to do afterwards with the votes (this rather assumes like a live process, or at least a kind of save button, as it is saved here in the local VotingApp state), I just save everything to the local state, how you would handle that is not really my intend to answer.



          So personally, I would rather go for one functional component, just rendering the news item and it's voting capability, where the voteCount is part of the item entity. If this is not how you receive the data, nothing stops you from adding the data after your fetch and before really showing it on the screen. The app itself will receive the changes and the item that will be changed, and what it does there-after, would be all up to you ;)






          const { Component } = React;

          const NewsItem = ( item ) => {
          const { subject, details, voteCount, handleVoteChange } = item;
          return (
          <div className="news-item">
          <div className="news-vote">
          <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
          <div className="vote-count">{ voteCount }</div>
          <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
          </div>
          <div className="news-content">
          <h3>{ subject }</h3>
          <div>{ details }</div>
          </div>
          </div>
          );
          };

          class VotingApp extends Component {
          constructor( props ) {
          super();
          this.handleVoteChange = this.handleVoteChange.bind( this );
          // by lack of fetching I add the initial newsItems to the state
          // and work by updating local state on voteChanges
          // depending on your state management (I guess you want to do something with the votes)
          // you could change this
          this.state = {
          newsItems: props.newsItems
          };
          }
          handleVoteChange( item, increment ) {
          this.setState( ( prevState ) => {
          const { newsItems } = prevState;
          // updates only the single item that has changed
          return {
          newsItems: newsItems
          .map( oldItem => oldItem.id === item.id ?
          { ...oldItem, voteCount: oldItem.voteCount + increment } :
          oldItem ) };
          } );
          }
          render() {
          const { newsItems = } = this.state;
          return (
          <div className="kiosk">
          { newsItems.map( item => <NewsItem
          key={ item.id }
          {...item}
          handleVoteChange={this.handleVoteChange} /> ) }
          </div>
          );
          }
          }

          // some bogus news items
          const newsItems = [
          { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
          { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
          { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
          ];

          // render towards the container
          const target = document.querySelector('#container');
          ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

          .kiosk {
          display: flex;
          flex-wrap: no-wrap;
          }
          .news-item {
          display: flex;
          justify-content: flex-start;
          width: 100%;
          }
          .news-vote {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding-left: 10px;
          padding-right: 10px;
          }
          .news-vote > * {
          cursor: pointer;
          }
          .news-content {
          display: flex;
          flex-direction: column;
          }
          .vote-up::before {
          content: '▲';
          }
          .vote-down::before {
          content: '▼';
          }
          .vote-up:hover, .vote-down:hover {
          color: #cfcfcf;
          }
          h3 { margin: 0; }

          <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
          <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
          <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
          <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
          <div id="container"></div>








          share|improve this answer












          I cannot really see how you would like to see voting as part of the local component state, as it really has to do (in my opinion), with the entities on which you can vote.



          So if I were you, I would rewrite the code slightly different. As I do not know what you intend to do afterwards with the votes (this rather assumes like a live process, or at least a kind of save button, as it is saved here in the local VotingApp state), I just save everything to the local state, how you would handle that is not really my intend to answer.



          So personally, I would rather go for one functional component, just rendering the news item and it's voting capability, where the voteCount is part of the item entity. If this is not how you receive the data, nothing stops you from adding the data after your fetch and before really showing it on the screen. The app itself will receive the changes and the item that will be changed, and what it does there-after, would be all up to you ;)






          const { Component } = React;

          const NewsItem = ( item ) => {
          const { subject, details, voteCount, handleVoteChange } = item;
          return (
          <div className="news-item">
          <div className="news-vote">
          <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
          <div className="vote-count">{ voteCount }</div>
          <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
          </div>
          <div className="news-content">
          <h3>{ subject }</h3>
          <div>{ details }</div>
          </div>
          </div>
          );
          };

          class VotingApp extends Component {
          constructor( props ) {
          super();
          this.handleVoteChange = this.handleVoteChange.bind( this );
          // by lack of fetching I add the initial newsItems to the state
          // and work by updating local state on voteChanges
          // depending on your state management (I guess you want to do something with the votes)
          // you could change this
          this.state = {
          newsItems: props.newsItems
          };
          }
          handleVoteChange( item, increment ) {
          this.setState( ( prevState ) => {
          const { newsItems } = prevState;
          // updates only the single item that has changed
          return {
          newsItems: newsItems
          .map( oldItem => oldItem.id === item.id ?
          { ...oldItem, voteCount: oldItem.voteCount + increment } :
          oldItem ) };
          } );
          }
          render() {
          const { newsItems = } = this.state;
          return (
          <div className="kiosk">
          { newsItems.map( item => <NewsItem
          key={ item.id }
          {...item}
          handleVoteChange={this.handleVoteChange} /> ) }
          </div>
          );
          }
          }

          // some bogus news items
          const newsItems = [
          { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
          { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
          { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
          ];

          // render towards the container
          const target = document.querySelector('#container');
          ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

          .kiosk {
          display: flex;
          flex-wrap: no-wrap;
          }
          .news-item {
          display: flex;
          justify-content: flex-start;
          width: 100%;
          }
          .news-vote {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding-left: 10px;
          padding-right: 10px;
          }
          .news-vote > * {
          cursor: pointer;
          }
          .news-content {
          display: flex;
          flex-direction: column;
          }
          .vote-up::before {
          content: '▲';
          }
          .vote-down::before {
          content: '▼';
          }
          .vote-up:hover, .vote-down:hover {
          color: #cfcfcf;
          }
          h3 { margin: 0; }

          <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
          <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
          <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
          <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
          <div id="container"></div>








          const { Component } = React;

          const NewsItem = ( item ) => {
          const { subject, details, voteCount, handleVoteChange } = item;
          return (
          <div className="news-item">
          <div className="news-vote">
          <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
          <div className="vote-count">{ voteCount }</div>
          <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
          </div>
          <div className="news-content">
          <h3>{ subject }</h3>
          <div>{ details }</div>
          </div>
          </div>
          );
          };

          class VotingApp extends Component {
          constructor( props ) {
          super();
          this.handleVoteChange = this.handleVoteChange.bind( this );
          // by lack of fetching I add the initial newsItems to the state
          // and work by updating local state on voteChanges
          // depending on your state management (I guess you want to do something with the votes)
          // you could change this
          this.state = {
          newsItems: props.newsItems
          };
          }
          handleVoteChange( item, increment ) {
          this.setState( ( prevState ) => {
          const { newsItems } = prevState;
          // updates only the single item that has changed
          return {
          newsItems: newsItems
          .map( oldItem => oldItem.id === item.id ?
          { ...oldItem, voteCount: oldItem.voteCount + increment } :
          oldItem ) };
          } );
          }
          render() {
          const { newsItems = } = this.state;
          return (
          <div className="kiosk">
          { newsItems.map( item => <NewsItem
          key={ item.id }
          {...item}
          handleVoteChange={this.handleVoteChange} /> ) }
          </div>
          );
          }
          }

          // some bogus news items
          const newsItems = [
          { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
          { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
          { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
          ];

          // render towards the container
          const target = document.querySelector('#container');
          ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

          .kiosk {
          display: flex;
          flex-wrap: no-wrap;
          }
          .news-item {
          display: flex;
          justify-content: flex-start;
          width: 100%;
          }
          .news-vote {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding-left: 10px;
          padding-right: 10px;
          }
          .news-vote > * {
          cursor: pointer;
          }
          .news-content {
          display: flex;
          flex-direction: column;
          }
          .vote-up::before {
          content: '▲';
          }
          .vote-down::before {
          content: '▼';
          }
          .vote-up:hover, .vote-down:hover {
          color: #cfcfcf;
          }
          h3 { margin: 0; }

          <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
          <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
          <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
          <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
          <div id="container"></div>





          const { Component } = React;

          const NewsItem = ( item ) => {
          const { subject, details, voteCount, handleVoteChange } = item;
          return (
          <div className="news-item">
          <div className="news-vote">
          <div className="vote-up" title="Vote up" onClick={ () => handleVoteChange( item, 1 ) }></div>
          <div className="vote-count">{ voteCount }</div>
          <div className="vote-down" title="Vote down" onClick={ () => handleVoteChange( item, -1 ) }></div>
          </div>
          <div className="news-content">
          <h3>{ subject }</h3>
          <div>{ details }</div>
          </div>
          </div>
          );
          };

          class VotingApp extends Component {
          constructor( props ) {
          super();
          this.handleVoteChange = this.handleVoteChange.bind( this );
          // by lack of fetching I add the initial newsItems to the state
          // and work by updating local state on voteChanges
          // depending on your state management (I guess you want to do something with the votes)
          // you could change this
          this.state = {
          newsItems: props.newsItems
          };
          }
          handleVoteChange( item, increment ) {
          this.setState( ( prevState ) => {
          const { newsItems } = prevState;
          // updates only the single item that has changed
          return {
          newsItems: newsItems
          .map( oldItem => oldItem.id === item.id ?
          { ...oldItem, voteCount: oldItem.voteCount + increment } :
          oldItem ) };
          } );
          }
          render() {
          const { newsItems = } = this.state;
          return (
          <div className="kiosk">
          { newsItems.map( item => <NewsItem
          key={ item.id }
          {...item}
          handleVoteChange={this.handleVoteChange} /> ) }
          </div>
          );
          }
          }

          // some bogus news items
          const newsItems = [
          { id: 1, voteCount: 0, subject: 'Mars in 2020', details: 'Tesla will send manned BFR rockets to Mars in 2020' },
          { id: 2, voteCount: -3, subject: 'Stackoverflow rocks', details: 'Stackoverflow is booming thanks to the new friendly policy' },
          { id: 3, voteCount: 10, subject: 'DS9: Healthy living', details: 'Eat rice everyday and drink only water, and live 10 years longer, says Dax to Sisko, Sisko suprises her by saying that like that, he doesn't want to live 10 years longer...' }
          ];

          // render towards the container
          const target = document.querySelector('#container');
          ReactDOM.render( <VotingApp newsItems={ newsItems } />, target );

          .kiosk {
          display: flex;
          flex-wrap: no-wrap;
          }
          .news-item {
          display: flex;
          justify-content: flex-start;
          width: 100%;
          }
          .news-vote {
          display: flex;
          flex-direction: column;
          align-items: center;
          padding-left: 10px;
          padding-right: 10px;
          }
          .news-vote > * {
          cursor: pointer;
          }
          .news-content {
          display: flex;
          flex-direction: column;
          }
          .vote-up::before {
          content: '▲';
          }
          .vote-down::before {
          content: '▼';
          }
          .vote-up:hover, .vote-down:hover {
          color: #cfcfcf;
          }
          h3 { margin: 0; }

          <script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
          <script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
          <script id="prop-types" src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
          <script id="classnames" src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
          <div id="container"></div>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 20 at 0:12









          Icepickle

          8,43232034




          8,43232034






















              up vote
              1
              down vote













              A few things I noticed unrelated to your question.



              1) onVoting should be bound in your constructor or use onVoting = () => { ..... }



              2) in your render function you have onVote instead of onVoting



              On to your main question, in your state you are only maintaining one counter that is displayed and changed for all news elements. an easy way to get around this is to create a new react element for each news article that will handle the voting for each article.



              class parent extends Component {

              constructor(){
              super()

              this.state = {
              news: null,
              }
              }
              componentDidMount() {
              // fetch data from api and minipulate as needed
              this.setState({news: dataFromApi})
              }

              render() {
              return (
              <Content>
              {
              this.state.news.map((item, i)=>{
              return (
              <NewChildComponent data={item}/>
              )
              })
              }
              </Content>
              )
              }
              }

              class NewChildComponent extends Component {
              constructor() {
              super()
              this.state = {
              voting: 0,
              }
              }
              onVoting = (e) => {
              this.setState(prevState => ({
              voteCount: e.target.name === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
              }));
              }
              render () {
              const {data} = this.props;
              return (
              <Item key={data.uniqueID}>
              <text>
              {data.subject}
              {data.details}
              </text>
              <Votering>
              <img src="" onClick={this.onVoting} name="add"/>
              <div value={this.state.voteing}>{this.state.voteing}</div>
              <img src="" onClick={this.onVoting} name="min"/>
              </Votering>
              </Item>
              )
              }
              }


              A little background on why you should not bind in your render function. https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36




              Here’s why: The parent component is passing down an arrow function on
              props. Arrow functions are reallocated on every render (same story
              with using bind). So although I’ve declared User.js as a
              PureComponent, the arrow function in User’s parent causes the User
              component to see a new function being sent in on props for all users.
              So every user re-renders when any delete button is clicked. 👎




              Also why you should not use an index as a key in React.
              https://reactjs.org/docs/lists-and-keys.html




              We don’t recommend using indexes for keys if the order of items may
              change. This can negatively impact performance and may cause issues
              with component state. Check out Robin Pokorny’s article for an
              in-depth explanation on the negative impacts of using an index as a
              key. If you choose not to assign an explicit key to list items then
              React will default to using indexes as keys.



              Here is an in-depth explanation about why keys are necessary if you’re
              interested in learning more.







              share|improve this answer



























                up vote
                1
                down vote













                A few things I noticed unrelated to your question.



                1) onVoting should be bound in your constructor or use onVoting = () => { ..... }



                2) in your render function you have onVote instead of onVoting



                On to your main question, in your state you are only maintaining one counter that is displayed and changed for all news elements. an easy way to get around this is to create a new react element for each news article that will handle the voting for each article.



                class parent extends Component {

                constructor(){
                super()

                this.state = {
                news: null,
                }
                }
                componentDidMount() {
                // fetch data from api and minipulate as needed
                this.setState({news: dataFromApi})
                }

                render() {
                return (
                <Content>
                {
                this.state.news.map((item, i)=>{
                return (
                <NewChildComponent data={item}/>
                )
                })
                }
                </Content>
                )
                }
                }

                class NewChildComponent extends Component {
                constructor() {
                super()
                this.state = {
                voting: 0,
                }
                }
                onVoting = (e) => {
                this.setState(prevState => ({
                voteCount: e.target.name === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
                }));
                }
                render () {
                const {data} = this.props;
                return (
                <Item key={data.uniqueID}>
                <text>
                {data.subject}
                {data.details}
                </text>
                <Votering>
                <img src="" onClick={this.onVoting} name="add"/>
                <div value={this.state.voteing}>{this.state.voteing}</div>
                <img src="" onClick={this.onVoting} name="min"/>
                </Votering>
                </Item>
                )
                }
                }


                A little background on why you should not bind in your render function. https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36




                Here’s why: The parent component is passing down an arrow function on
                props. Arrow functions are reallocated on every render (same story
                with using bind). So although I’ve declared User.js as a
                PureComponent, the arrow function in User’s parent causes the User
                component to see a new function being sent in on props for all users.
                So every user re-renders when any delete button is clicked. 👎




                Also why you should not use an index as a key in React.
                https://reactjs.org/docs/lists-and-keys.html




                We don’t recommend using indexes for keys if the order of items may
                change. This can negatively impact performance and may cause issues
                with component state. Check out Robin Pokorny’s article for an
                in-depth explanation on the negative impacts of using an index as a
                key. If you choose not to assign an explicit key to list items then
                React will default to using indexes as keys.



                Here is an in-depth explanation about why keys are necessary if you’re
                interested in learning more.







                share|improve this answer

























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  A few things I noticed unrelated to your question.



                  1) onVoting should be bound in your constructor or use onVoting = () => { ..... }



                  2) in your render function you have onVote instead of onVoting



                  On to your main question, in your state you are only maintaining one counter that is displayed and changed for all news elements. an easy way to get around this is to create a new react element for each news article that will handle the voting for each article.



                  class parent extends Component {

                  constructor(){
                  super()

                  this.state = {
                  news: null,
                  }
                  }
                  componentDidMount() {
                  // fetch data from api and minipulate as needed
                  this.setState({news: dataFromApi})
                  }

                  render() {
                  return (
                  <Content>
                  {
                  this.state.news.map((item, i)=>{
                  return (
                  <NewChildComponent data={item}/>
                  )
                  })
                  }
                  </Content>
                  )
                  }
                  }

                  class NewChildComponent extends Component {
                  constructor() {
                  super()
                  this.state = {
                  voting: 0,
                  }
                  }
                  onVoting = (e) => {
                  this.setState(prevState => ({
                  voteCount: e.target.name === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
                  }));
                  }
                  render () {
                  const {data} = this.props;
                  return (
                  <Item key={data.uniqueID}>
                  <text>
                  {data.subject}
                  {data.details}
                  </text>
                  <Votering>
                  <img src="" onClick={this.onVoting} name="add"/>
                  <div value={this.state.voteing}>{this.state.voteing}</div>
                  <img src="" onClick={this.onVoting} name="min"/>
                  </Votering>
                  </Item>
                  )
                  }
                  }


                  A little background on why you should not bind in your render function. https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36




                  Here’s why: The parent component is passing down an arrow function on
                  props. Arrow functions are reallocated on every render (same story
                  with using bind). So although I’ve declared User.js as a
                  PureComponent, the arrow function in User’s parent causes the User
                  component to see a new function being sent in on props for all users.
                  So every user re-renders when any delete button is clicked. 👎




                  Also why you should not use an index as a key in React.
                  https://reactjs.org/docs/lists-and-keys.html




                  We don’t recommend using indexes for keys if the order of items may
                  change. This can negatively impact performance and may cause issues
                  with component state. Check out Robin Pokorny’s article for an
                  in-depth explanation on the negative impacts of using an index as a
                  key. If you choose not to assign an explicit key to list items then
                  React will default to using indexes as keys.



                  Here is an in-depth explanation about why keys are necessary if you’re
                  interested in learning more.







                  share|improve this answer














                  A few things I noticed unrelated to your question.



                  1) onVoting should be bound in your constructor or use onVoting = () => { ..... }



                  2) in your render function you have onVote instead of onVoting



                  On to your main question, in your state you are only maintaining one counter that is displayed and changed for all news elements. an easy way to get around this is to create a new react element for each news article that will handle the voting for each article.



                  class parent extends Component {

                  constructor(){
                  super()

                  this.state = {
                  news: null,
                  }
                  }
                  componentDidMount() {
                  // fetch data from api and minipulate as needed
                  this.setState({news: dataFromApi})
                  }

                  render() {
                  return (
                  <Content>
                  {
                  this.state.news.map((item, i)=>{
                  return (
                  <NewChildComponent data={item}/>
                  )
                  })
                  }
                  </Content>
                  )
                  }
                  }

                  class NewChildComponent extends Component {
                  constructor() {
                  super()
                  this.state = {
                  voting: 0,
                  }
                  }
                  onVoting = (e) => {
                  this.setState(prevState => ({
                  voteCount: e.target.name === "add" ? prevState.voteCount + 1 : prevState.voteCount - 1
                  }));
                  }
                  render () {
                  const {data} = this.props;
                  return (
                  <Item key={data.uniqueID}>
                  <text>
                  {data.subject}
                  {data.details}
                  </text>
                  <Votering>
                  <img src="" onClick={this.onVoting} name="add"/>
                  <div value={this.state.voteing}>{this.state.voteing}</div>
                  <img src="" onClick={this.onVoting} name="min"/>
                  </Votering>
                  </Item>
                  )
                  }
                  }


                  A little background on why you should not bind in your render function. https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36




                  Here’s why: The parent component is passing down an arrow function on
                  props. Arrow functions are reallocated on every render (same story
                  with using bind). So although I’ve declared User.js as a
                  PureComponent, the arrow function in User’s parent causes the User
                  component to see a new function being sent in on props for all users.
                  So every user re-renders when any delete button is clicked. 👎




                  Also why you should not use an index as a key in React.
                  https://reactjs.org/docs/lists-and-keys.html




                  We don’t recommend using indexes for keys if the order of items may
                  change. This can negatively impact performance and may cause issues
                  with component state. Check out Robin Pokorny’s article for an
                  in-depth explanation on the negative impacts of using an index as a
                  key. If you choose not to assign an explicit key to list items then
                  React will default to using indexes as keys.



                  Here is an in-depth explanation about why keys are necessary if you’re
                  interested in learning more.








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 19 at 23:42

























                  answered Nov 19 at 23:31









                  joshua fermin

                  384111




                  384111






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383864%2freact-counter-for-each-item-of-list%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      To store a contact into the json file from server.js file using a class in NodeJS

                      Redirect URL with Chrome Remote Debugging Android Devices

                      Dieringhausen