acd37
acd37

Reputation: 582

Props not loading in time for AJAX request

I've checked out several similar questions and tried to implement their answers, but still no luck. Here's the code:

import React, {Component, Fragment} from "react";
import Files from "./client/files";
import axios from "axios";

const styles = {
  card: {
      border: "1px solid transparent",
      borderRadius: "8px",
      padding: "20px",
      boxShadow: "0 1px 2px 0 rgba(60,64,67,0.302), 0 2px 6px 2px rgba(60,64,67,0.149)",
      maxWidth: "75%"
    },
  h1: {
    marginTop: "30px"
  },
  link: {
    color: '#000'
  },
  i: {
    fontSize: '24px',
    margin: '0 20px'
  },
  h4: {
    color: "#24486f",
    letterSpacing: "1.2px"
  },
  h5: {
    color: "#24486f",
    letterSpacing: "1.2px"
  }
}

class Client extends Component {

  constructor() {
    super();
    this.state = {
      client_files: [],
      user_id: "",
      client_name: "",
      version_ref: "",
      first_name: "",
      last_name: "",
      email: "",
      phone: "",
      website: "",
      file_refs: []
    };

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

    componentDidMount() {
      console.log(this.props.currentUser)
      this.getFileData();
    }

    getFileData() {

      let fileRefs = this.props.currentUser.file_refs;
      let fileData = [];

      for (let i = 0; i < fileRefs.length; i++) {
        axios.get("/api/file/get-file/" + fileRefs[i])
          .then( res => {
            console.log(res.data.response)
            fileData.push(res.data.response);
            this.setState({
              client_files: fileData
            })
          })
          .catch( err => console.log(err.response.data))
      }
    }

  render() {

      return(
      <Fragment>
        <div className="container">
          <div className="row">
            <div className="col-lg-12">
              <h1 style={styles.h1}> PartnerPortal </h1>
              <hr/>
                <h4 style={styles.h4}>
                  <em>Welcome, {this.props.currentUser.first_name} {this.props.currentUser.last_name}</em>
                </h4>
                <h5 style={styles.h5}>
                  <em>{ this.props.currentUser.client_name}</em>
                </h5>
                <hr/>

                <p> PartnerPortal allows you quick access to files, resources, and other documents that are part of your current contract with .... Company</p>

                <div style={styles.card}>
                      <table className="table">
                        <thead>
                          <tr>
                            <th scope="col">#</th>
                            <th scope="col">Type</th>
                            <th scope="col">File Name</th>
                          </tr>
                        </thead>
                        <tbody>
                          {this.state.client_files.map(( file, i ) => (
                            <tr key={i}>
                              <td>{i}</td>
                              <td style={styles.p}>
                                { file.file_type === "PDF" &&
                                  <a href={file.file_url}><span style={styles.link}><i style={styles.i} className="far fa-file-pdf"></i></span></a>
                                }
                                { file.file_type === "DOC" &&
                                  <a href={file.file_url}><span style={styles.link}><i style={styles.i} className="far fa-file-alt"></i></span></a>
                                }
                                { file.file_type === "Directory" &&
                                  <a href={file.file_url}><span style={styles.link}><i style={styles.i} className="far fa-folder"></i></span></a>
                                }
                                { file.file_type === "Presentation" &&
                                  <a href={file.file_url}><span style={styles.link}><i style={styles.i} className="far fa-file-powerpoint"></i></span></a>
                                }

                              </td>
                              <td>{file.file_name}</td>
                            </tr>
                          ))}
                      </tbody>
                      </table>

                </div>
            </div>
          </div>
        </div>
      </Fragment>
    );
  }
}

export default Client;

The currentUser is passed down as props from the parent component, and contains an array of file references (this.props.currentUser.file_refs). The console.log inside componentDidMount() accurately logs all the file references to the console. However, when the getFileData() function runs, it returns the error: TypeError: Cannot read property 'length' of undefined.

What I've already tried: - changing to componentWillMount() - adding if (this.props.currentUser){this.getFileData()) in my componentDidMount() function - adding if (!this.props.currentUser.file_refs) { return null ) return ( <Fragment> ..... </Fragment>

Anybody know what I'm doing wrong here?

Edit: Adding routes from parent component, Main.js

{ (isLoggedIn && currentUser.isAdmin) &&
          <Route exact path="/" render={() => (<IodDash currentUser={this.props.currentUser}/>)}/>
        }

    { (isLoggedIn && !currentUser.isAdmin) &&
      <Route exact path="/" render={() => (<ClientDash currentUser={this.props.currentUser}/>)}/>
    }

Upvotes: 1

Views: 49

Answers (1)

tylern
tylern

Reputation: 64

It looks like this.props.currentUser.file_refs isn't fully loaded before setting it to the fileRefs variable in your function getFileData() and that is why you are getting the error TypeError: Cannot read property 'length' of undefined. You might want to write a check in the parent component that makes sure the data is loaded before passing the prop to the child.

Upvotes: 1

Related Questions