Alan Maldonado
Alan Maldonado

Reputation: 133

React: Update component data/props after promise resolved

I'm a bit new to React and I've been having some problems understanding the workarounds of certain methods that I've used in other languages.

The Problem:

What I was hoping to achieve is that whenever the user clicks a button, the app will render a new section displaying some variable values. What I did was that when the user clicked a button, an state changed, and let the new Component render, and I passed the data through its props.

The problem is, If I understand correctly, that I'm passing the old values when I create the component and not the actual/updated values that I want to render...

Let's say I have this following variables.

const user_data = {
   pic_url: 'null',
   followers: 'Loading...',
   followings: 'Loading...',
   nTweets: 'Loading...',
};

Those variables are going to change value whenever the user click a button.

This next block of code is what I use to render the next component where I want the new values.

const SomeComponent = props => {
  const [resolved, setResolved] = useState({ display: false });

  const displayValidation = props => {
    setResolved({ ...resolved, display: !resolved.display });
  };

function getData(username) {
        const url = 'https://www.twitter.com/' + username;
        getHTML(url)
          .then(res => {
            getUserData(res).then(res => {
              user_data.followers = res.followers;
              user_data.followings = res.followings;
              user_data.nTweets = res.nTweets;
              user_data.pic_url = res.pic_url;
              console.log('Updated data:', user_data);
              displayValidation();
            });
          })
          .catch(function(error) {
            console.error('Username was not found.');
          });
      }

      const handleSubmit = event => {
        event.preventDefault();
        console.log('Resolving data...');
        getData(user.username);
      };

      return (
        <React.Fragment>
          <Navbar />
          <div className="container lg-padding">
            <div className="row" id="getTracker">
              <div className="col-sm-12 center">
                <div className="card text-center hoverable">
                  <div className="card-body">
                    <div className="input-field">
                      <i className="material-icons prefix">account_circle</i>
                      <input
                        id="username"
                        type="text"
                        className="validate"
                        value={user.username}
                        onChange={handleChange}
                      />
                      <label htmlFor="username">Enter a username to track</label>
                    </div>
                    <input
                      type="button"
                      onClick={handleSubmit}
                      value="Track"
                      className="btn-large blue darken-4 waves-effect waves-light"
                    />
                  </div>
                </div>
              </div>
            </div>
            <div className="row">
              <div className="col-sm-12">
                **{resolved.display && <DisplayData type={1} data={user_data} />}**
              </div>
            </div>
          </div>
          <Footer />
        </React.Fragment>
      );
    };

I want to see the new values, but it always render the first values that I passed when creating the component.

This is the component that I create

import React from 'react';

const DisplayData = props => {
  const user = props.data;
  console.log('Display', user);
  switch (props.type) {
    case 1: //Twitter
      return (
        <React.Fragment>
          <div className="row lg-padding">
            <div className="col-sm-12 lg-padding center">
              <img
                src={user.pic_url}
                alt="profile_picture"
                style={{ width: 50 + '%' }}
              />
            </div>
            <h2>{user.username}</h2>
          </div>
          <div className="row lg-padding">
            <div className="col-sm-4">
              <h4>Tweets: {user.nTweets}</h4>
            </div>
            <div className="col-sm-4">
              <h4>Followers: {user.followers}</h4>
            </div>
            <div className="col-sm-4">
              <h4>Followings: {user.followings}</h4>
            </div>
          </div>
        </React.Fragment>
      );

    case 2: //Instagram
      return <React.Fragment />;

    default:
      return (
        <React.Fragment>
          <div className="row lg-padding">
            <div className="col-sm-12 lg-padding center">
              <img
                src={user.pic_url}
                alt="profile_picture"
                style={{ width: 50 + '%' }}
              />
              <h2>Instagram_User</h2>
              <h4>Posts: ND</h4>
              <h4>Followers: ND</h4>
              <h4>Followings: ND</h4>
            </div>
          </div>
        </React.Fragment>
      );
  }
};

export default DisplayData;

How can I update the data in the component or render the component when the data is updated?

Upvotes: 3

Views: 1532

Answers (1)

Luiz Fernando da Silva
Luiz Fernando da Silva

Reputation: 1499

Maybe your user_data might to be a state object.

// Somecomponent ...
const [user_data, setUser_data] = useState({
   pic_url: 'null', 
   followers: 'Loading...', 
   followings: 'Loading...',  
   nTweets: 'Loading...'
})
/* Rest of stuff */

const handleSubmit = async event => {
/*...*/
    const userData = await getData(user.username)
    setUser_data(userData)
}

// Then display the stated-stored user_data
<div className="col-sm-12">
      **{resolved.display && <DisplayData type={1} data={user_data} />}**
</div>

Upvotes: 3

Related Questions