简体   繁体   中英

When I map over a populated array in this.state, why does it return undefined?

In my app I have a home component that is rendered after a user logins. In this home component's componentDidMount I fetch the documents associated with the logged in user. The fetch call works and the response is populated with the correct data. I take this data and make a this.setState call, setting the fetched data to this.state.

In the home components render function I insert JSX that calls a function to map over this.state.docs and display that data. Even though the data in this.state can be logged successfully in the Home component's render function, the result of mapping over the data always returns undefined.

If i create a new document it does get inserted and displays correctly, but the older documents never display.

Here's my home component:

import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';

const axiosConfig = {
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json'
  }
};

class Home extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      docs: [],
      username: '',
      userid: '',
      newDocumentName: '',
      newDocumentPassword: '',
      loading: true
    };
    console.log('this.props in home constructor ', this.props);
  }

  newDoc() {
    console.log('this.state before new doc ', this.state);
    axios(localStorage.getItem('url') + '/newDoc', {
      method: 'post',
      data: {
        title: this.state.newDocumentName,
        password: this.state.newDocumentPassword
      },
      withCredentials: true
    }).then(resp => {
      console.log('the response to new doc ', resp);
      this.setState({
        docs: [...this.state.docs, resp.data.document],
        newDocumentName: '',
        newDocumentPassword: ''
      });
    });
  }

  renderDocumentList() {
    return this.state.docs.map((doc, i) => (
      <div key={i}>
        <Link to={`/editDocument/${doc._id}`}>{doc.title}</Link>
      </div>
    ));
  }

  logout() {
    axios
      .post('http://localhost:3000/logout')
      .then(resp => {
        this.props.history.replace('/');
      })
      .catch(error => console.log(error));
  }

  async componentDidMount() {
    try {
      let resp = await axios
        .get(
          localStorage.getItem('url') +
            '/getAllDocs/' +
            this.props.match.params.userid,
          axiosConfig
        )
        .then(resp => {
          console.log('awaited response in comp did mount of home ', resp);
          this.setState({
            docs: [resp.data.docs],
            username: resp.data.username,
            userid: resp.data.userid,
            loading: false
          });
        });
    } catch (e) {
      console.log(e);
    }
  }

  render() {
    if (this.state.loading) {
      return (
        <div>
          <h2>Loading...</h2>
        </div>
      );
    } else {
      return (
        <div className="page-container">
          <div className="document-header">
            <button className="logout-button" onClick={() => this.logout()}>
              Logout
            </button>
            <h3>Welcome, {this.state.username}.</h3>
          </div>
          <div className="create-or-share-document-div">
            <input
              type="text"
              placeholder="New document name"
              name="newDocumentName"
              value={this.state.newDocumentName || ''}
              onChange={event => {
                this.setState({ newDocumentName: event.target.value });
              }}
              style={{ width: '30%' }}
            />
            <input
              type="password"
              placeholder="new document password"
              name="newDocumentPassword"
              value={this.state.newDocumentPassword || ''}
              onChange={event => {
                this.setState({ newDocumentPassword: event.target.value });
              }}
              style={{ width: '30%' }}
            />
            <button
              style={{
                border: 'solid black 1px',
                padding: '5px',
                borderRadius: '10px',
                height: '3%',
                backgroundColor: 'lightgrey'
              }}
              onClick={() => this.newDoc()}
            >
              Create Document
            </button>
          </div>
          <div className="document-container">
            <div className="document-list">
              <p>My Documents:</p>
              <ul>{this.renderDocumentList()}</ul>
            </div>
          </div>
          <br />
          <div className="create-or-share-document-div">
            <input
              style={{ width: '30%' }}
              type="text"
              placeholder="paste a docID to collab on a doc"
              ref="sharedDoc"
            />
            <button
              style={{
                border: 'solid black 1px',
                padding: '5px',
                borderRadius: '10px',
                height: '3%',
                backgroundColor: 'lightgrey'
              }}
            >
              Add Shared Doc
            </button>
          </div>
        </div>
      );
    }
  }
}

export default Home;

You are setting the docs in state to [resp.data.docs] , which is an array inside of an array. Use the resp.data.docs array directly instead:

this.setState({
  docs: resp.data.docs,
  username: resp.data.username,
  userid: resp.data.userid,
  loading: false
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM