0

So I have a simple app I am building out and am pulling all the data from a sample API and so far it looks like this:

enter image description here

Am sampling out data of users from this API. What I am trying to do here now is add a simple button that increments the count of kudos for any user. Mind you, I am not authenticating a particular user when entering as of yet.

This said, my code is as follows:

My app.js looks like:

import React, { Component } from 'react';
import './App.css';

import KudoList from "./components/KudoList";

import axios from "axios";

class App extends Component {

  state = {
    contacts: []
  };

  componentDidMount() {
    axios
      .get("https://kudos-devtech8-yvbvpoek.herokuapp.com/users")
      .then(response => {
        const newContacts = response.data.map(c => {
          return {
            id: c.id,
            name: c.username,
            fname: c.first_name,
            lname: c.last_name,
            kgive: c.kudos_given_count,
            kreceived: c.kudos_received_count
          };
        });

        const newState = Object.assign({}, this.state, {
          contacts: newContacts
        });

        this.setState(newState);
      })
      .catch(error => console.log(error));
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">Welcome to our Kudo app</h1>
        </header>
        <KudoList contacts={this.state.contacts} />
      </div>
    );
  }
}

export default App;

The above pulls from a KudoList.js that is essentially my component that then pulls from a Contact.js component to form the UI you see in the screenshot.

KudoList.js:

import React from "react";
import Contact from "./Contact";

function KudoList(props) {
  return (
    <div>
        {props.contacts.map(c => <Contact key={c.id} name={c.name} fname={c.fname} lname={c.lname} kgive={c.kgive} kreceived={c.kreceived} /> )}
    </div>
  );
}

export default KudoList;

And then Contact.js:

import React from "react";
import "./Contact.css";

class Contact extends React.Component {
    state = { kgive: 0,
              fname: '',
              lname: '',
              kreceived: ''
    };

    constructor(props) {
      super(props);

      this.incrementKudoCount = this.incrementKudoCount.bind(this);
    }

    incrementKudoCount(ev) {
      this.setState((prevState) => ({
        kgive: prevState.kgive + 1,
      }));
    }

    render() {
      return (
        <div className="appPerson">
          <p>Name: {this.props.fname} {this.props.lname} <button onClick={this.incrementKudoCount}>Give Kudo!</button></p>
          <p>Kudos Given: {this.props.kgive}</p>
          <p>Kudos Received: {this.props.kreceived}</p>
        </div>
      );
    }
  }

export default Contact;

You can see where I commented out state and function I thought was best to add to the list, but if I am mapping this list and wanting to bind a button next to each kudo count, I was getting mixed up on the best way to do this. Am sure I am missing something simple. Any help is much appreciated on this.

2 Answers 2

1

This should be what you are wanting. You want to use a class instead of a function because you want to maintain the state. So we need to first initialize the starting state value, and then we need to bind the context of the function to the class. You will need to bind the function context, because when you pass it to the onClick function, it will lose access to the class properties, binding it prevents this.

class Contact extends React.Component {
  state = { kudos: 0 };

  constructor(props) {
    super(props);

    this.incrementKudoCount = this.incrementKudoCount.bind(this);
  }

  incrementKudoCount(ev) {
    this.setState((prevState) => ({
      kudos: prevState.kudos + 1,
    }));
  }

  render() {
    return (
      <div className="appPerson">
        <p>Name: {props.fname} {props.lname}</p>
        <p>Kudos Given: {this.state.kudos}</p>
        <p>Kudos Received: {props.kreceived}</p>
        <button onClick={this.incrementKudoCount}>Give Kudo!</button>
      </div>
    );
  }
}

One thing is that this is not a persistent count. If you were want to the count to persist across many users and visits, you would need to add this backend logic. You could still do the network call in your incrementKudoCount, but it could be worth while looking into something like redux if you plan to build more user to network interactions.

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

5 Comments

makes sense, but an issue with the button and increment. What I have now is:
class Contact extends React.Component { state = { kgive: 0 }; constructor(props) { super(props); this.incrementKudoCount = this.incrementKudoCount.bind(this); } incrementKudoCount(ev) { this.setState((prevState) => ({ kgive: prevState.kgive + 1, })); } render() { return ( <div className="appPerson"> <p>Name: {this.props.fname} {this.props.lname} <button onClick={this.incrementKudoCount}>Give Kudo!</button></p> <p>Kudos Given: {this.props.kgive}</p> <p>Kudos Received: {this.props.kreceived}</p> </div> ); } }
Please excuse my formatting as I could not get it to format correctly and show my code in the response.
the issue with the way I have it here is that the button clicks, but nothing happens. Even trying to add props for others, it is not changing the count. Will update source in original question.
@Mark Okay I understand, you need to change the <p>Kudos Given: {props.kgive}</p> to <p>Kudos Given: {this.state.kudos}</p>. We were updating the state but never actually displaying it in the UI.
0

The best way for your APP it's to use Context API it was release since the 16.0 React version.

It's a good way to started with that, this feature help you to using a state management, you can store all of this at the top of you application for example.

And you can re-use this, where are you want.

For a average or bigger application you can use a Redux.

Please see that documentation for more information about Context API :

About Context API

Comments

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.