dealwap
dealwap

Reputation: 721

How to display data from api in react component

I am using axios to get data from an API and the retrieved data was successfully dispatched to the store, I currently have some problems in displaying the data in my React component.

I was able to console.log the data successfully but it turns out my component renders before the data was fully retrieved from the API.

Below is the component to display the data:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import HeaderSidebar from './includes/header-navbar';
import AllBooks from './includes/all-books';
import { getAllBooks } from '../../actions/book_actions';


class AdminHome extends Component {

componentDidMount() {
    this.props.actions.getAllBooks();
}

renderBooks(){
    const allbooks = this.props.books;

    return allbooks.map((book) => {
        return (<div key={book.id}>
            <AllBooks title={book.title}
            description={book.description}
            />
        </div>)
    })
}
render() {
    return (
        <div >
            <HeaderSidebar />
          {this.renderBooks()}
            })}
            })}
        </div >
    )
  }
}

  function mapStateToProps(state) {
    return {
    books: state.book.data
  }
}

 AdminHome.PropTypes = {
  books: PropTypes.object.isRequired
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({
        getAllBooks
    }, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AdminHome);

Actions

export function getAllBooks() {
  return dispatch => axios.get(`${API_URL}`)
    .then((res) => {
      dispatch({
        type: GET_ALL_BOOKS,
        data: res.data
      });
      return res.data;
    })
    .catch(error => error);
}

Reducers import { ADD_BOOK, GET_ALL_BOOKS } from '../actions/types';

const INITIAL_STATE = {};

function bookReducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case ADD_BOOK:
      return { ...state, message: 'Book added Successfully' };
    case GET_ALL_BOOKS:
      return { ...state, data: action.data };
    default:
      return state;
  }
}

export default bookReducer;

Upvotes: 1

Views: 1162

Answers (1)

jonahe
jonahe

Reputation: 5010

You can show something else until the data is done loading

renderBooks(){
if(!this.props.books) {
  return (<p>Loading data..<p/>);
}


// rest of your code here 

Or you can initialize the property with an empty array so that at least nothing crashes until the data is done loading.

function mapStateToProps(state) {
  return {
    books: state.book.data || []  //  maybe have to extra checks here if state.book doesn't exist yet
}

(Or do both, and change if(!this.props.books) to if(this.props.books.length < 1).

Upvotes: 3

Related Questions