0
\$\begingroup\$

I have two fetch calls which updates the state. And I have two buttons. One makes a fetch call, another calls componentDidMount().

The first fetch call is in componentDidMount().

The second is On "All Time Sort" button click with handleSortRecent().

On "Recent Sort" button click, I want to show the previous informatin fetched in componentDidMount. To achieve this I am calling the componentDidMount() method itself from handleSortRecent() method.

Is there a better way to do this without using Redux?

const API = "https://fcctop100.herokuapp.com/api/fccusers/top/";

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      dataRecent : [],
      dataAlltime : []
    }

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
    this.handleSortRecent = this.handleSortRecent.bind(this);
  }

  componentDidMount() {
    fetch(API+"recent")
      .then( response => response.json() )
      .then( data => this.setState( { dataRecent: data } ) );
  }

  handleClick () {
    fetch(API+"alltime")
    .then(response => response.json())
    .then(data => this.setState({dataRecent:data}))
  }

  handleSortRecent() {
    this.componentDidMount();
  }

  render() {
    const arrRecentList = this.state.dataRecent;

    return (
      <div className="App">
      <button onClick={this.handleClick}>All Time Sort</button>
      <button onClick={this.handleSortRecent}>Recent Sort</button>
      {
        arrRecentList.map(data =>
          <div key={data.username}>
            <img src={data.img} width="50px" alt="" />
            <a href={"https://www.freecodecamp.org/"+data.username} target="_blank">{data.username}</a>
            <span> - </span>
            <span>{data.recent}</span>
            <span> - </span>
            <span>{data.alltime}</span>
          </div>
        )
      }
      </div>
    );
  }
}

\$\endgroup\$
1

1 Answer 1

2
\$\begingroup\$

It's strange that you would call this.componentDidMount. I have not seen this before. Either way, what if you created an indicator in your state that declared what should be shown? For example:

this.state = {
  dataRecent : [],
  dataAlltime : [],
  display: "recent"
}

Then inside of your render function you can choose what gets displayed.

this.state.display === 'recent' 
  ? this.state.dataRecent.map...
  : this.state.dataAlltime.map...

I would create two functions that handle getting both sets of data.

getAlltimeData() => {
   fetch(API+"alltime")
    .then(response => response.json())
    .then(data => this.setState({ dataRecent:data }))
}

getRecentData() => {
   fetch(API+"recent")
    .then(response => response.json())
    .then(data => this.setState({ dataRecent:data }))
}

You can then call both of them when the component mounts.

componentDidMount() {
  this.getAlltimeData();
  this.getRecentData();
}

At this point you have the data you need. What you don't have is a click handler to switch between recent and all time.

handleRecentClick() {
  this.setState({ display: 'recent' });
}

handleAlltimeClick() {
  this.setState({ display: 'allTime' });
}

Pass those to the buttons that change state respectively.

 <button onClick={this.handleRecentClick}>All Time Sort</button>
 <button onClick={this.handleAlltimeClick}>Recent Sort</button>

Make sure to bind your functions in the constructor like you did with the others.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.