Mark
Mark

Reputation: 1872

Binding onClick element to React component for remote API

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.

Upvotes: 0

Views: 342

Answers (2)

kyle
kyle

Reputation: 2638

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.

Upvotes: 1

KolaCaine
KolaCaine

Reputation: 2187

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

Upvotes: 0

Related Questions