问题
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