How to use react stateless component when API response didn't got yet?

荒凉一梦 提交于 2019-12-11 15:50:47

问题


I'm working with react in Laravel, and i'm trying to built a simple FriendsList component to display data from API. The problem is that the Parent (Profile) component is finish loading before it's get the data, so the FriendsList component return an error, because the props are empty for the first time. It's important to say that regardless of the API response - the parent (Profile) component works well, it's loaded for the first time empty - and then the data is adding.

The Api call

 export const getProfile = () => {
 return axios
     .get('api/profile', {
        headers: { Authorization: `Bearer ${localStorage.usertoken}` }
     })
    .then(response => {
        // console.log(response.data)
        return response.data
    })
    .catch(err => {
        console.log(err)
    })
 }

The Parent Component

        import React, { Component } from 'react'
        import { getProfile } from './UserFunctions'
        import FriendsList from './FriendsList';

        class Profile extends Component {
            constructor() {
                super()
                this.state = {
                    name: '',
                    hobbies: '',
                    user_bday: '',
                    members: [],
                    error: '',

                }

            }

            componentDidMount() {

                getProfile().then(res => {
                    //   console.log(JSON.parse(res))
                    this.setState({
                        name: res.user.name,
                        hobbies: res.user.hobbies,
                        user_bday: res.user.user_birthday,
                        related_friends: res.user.related_friends,
                        members: res.user.members,

                    })

                })
            }


            render() {

                return (
                    <div className="container">
                        <div className="jumbotron mt-5">
                            <div className="col-sm-4 mx-auto">
                                <h1 className="text-center">PROFILE</h1>
                            </div>
                            <table className="table col-md-4 mx-auto">
                                <tbody>
                                    <tr>
                                        <td>Name</td>
                                        <td>{this.state.name}</td>
                                        <td>{this.state.hobbies}</td>
                                        <td>{this.state.user_bday}</td>

                                    </tr>
                                </tbody>
                            </table>
                            <FriendsList members={this.state.members}> 
       </FriendsList>
                        </div>
                    </div>
                )
            }
        }

        export default Profile

    import React from 'react';
     class FriendsList extends React.Component {

      render() {
        console.log(this.props)
        const { members } = this.props;
        const listmembers = members.map((item, index) => (
          <li key={item + index}>{item.name}</li>
        ));
        return (
          <div>
            {listmembers}
          </div>
        );
      }
    }
    export default FriendsList

回答1:


There are a couple of ways to go about this.

First approach:

class Profile extends Component {
  render() {
    // check if your `state` has all the necessary values
    // before rendering your JSX

    const { name, hobbies, user_bday, members } = this.state
    const shouldRender = name !== '' && 
      hobbies !== '' &&
      user_bday !== '' &&
      Array.isArray(members) && members.length > 0

    if (!shouldRender) {
      return null;
    }
    return (...)
  }
}

This way, you're only rendering JSX when your state has everything that you need.


Second approach:

class Profile extends Component {
  constructor() {
    // ...
    this.setState = {
      members: []
    }
  }
}

Set your members to an empty array, rather than an empty string, so that way when you're passing it as prop to FriendList component, calling this.props.friends.map is actually correct, but it won't render anything since the array is initially empty.


Also, it looks like you are never updating your members after your API call finishes:

componentDidMount() {
  getProfile().then(res => {
    this.setState({
      name: res.user.name,
      hobbies: res.user.hobbies,
      user_bday: res.user.user_birthday,
      related_friends: res.user.related_friends,
    })
  })
}

So your members actually stays as an empty string. Make sure your updating your state with the right type, which in this case should be an array.




回答2:


if I understood your question I guess you need to take a look at https://www.npmjs.com/package/prop-types, I think your problem is with the default props value and this library could help you achieve the wanted behavior.




回答3:


If I understood the question correctly you're talking about null props... Also, Kellen in the comments is correct... You should set members to an empty array instead and I do not see you updating the state for members in your setState...

Try:

render() {
    const friendsList =
        this.props.firends &&
        this.props.friends.map(function(item, index) {
            <li key={index}>{item.name}</li>;
        });

    return (
        <div>
            <ul>{friendsList}</ul>
        </div>
    );
}



回答4:


Another approach here would be to use loading state, during which you'll show a loading indicator, etc.

class Profile extends Component {
  constructor() {
    super();
    this.state = {
      name: "",
      hobbies: "",
      user_bday: "",
      members: "",
      error: "",
      isMembers: false,
      loading: true // Add loading state
    };
  }

  componentDidMount() {
    getProfile().then(res => {
      //   console.log(JSON.parse(res))
      this.setState({
        name: res.user.name,
        hobbies: res.user.hobbies,
        user_bday: res.user.user_birthday,
        related_friends: res.user.related_friends,
        loading: false // Remove the loading state when data is fetched
      });
    });
  }

  render() {
    return this.state.loading ? (
      <p> Loading... </p>
    ) : (
      <div className="container">
        <div className="jumbotron mt-5">
          <div className="col-sm-4 mx-auto">
            <h1 className="text-center">PROFILE</h1>
          </div>
          <table className="table col-md-4 mx-auto">
            <tbody>
              <tr>
                <td>Name</td>
                <td>{this.state.name}</td>
                <td>{this.state.hobbies}</td>
                <td>{this.state.user_bday}</td>
              </tr>
            </tbody>
          </table>
          {/*<FriendsList friends={this.state.members}></FriendsList>*/}
        </div>
      </div>
    );
  }
}



来源:https://stackoverflow.com/questions/57441990/how-to-use-react-stateless-component-when-api-response-didnt-got-yet

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!