目标:
我希望能够从数组中获取多个配置文件并将其列在屏幕上。类似的东西:
John, Sandy, Drew
我正在使用react并尝试从friendRequest
数组中列出用户。这个数组充满了用户ID,我想映射它们以获取用户并在屏幕上显示他/她。
正在发生的事情是,在console.log(pendingFriend)
中,它是一个无限循环,在这种情况下,两个配置文件一遍又一遍地被记录。屏幕上也没有显示jsx。
这是代码。
查看渲染>返回>你看到currentUser.friendRequests
被映射的地方。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import swal from 'sweetalert';
import actions from '../../actions';
import { UpdateProfile } from '../view';
import { DateUtils } from '../../utils';
class Profile extends Component {
constructor() {
super();
this.state = {
profile: {
image:
'https://lh3.googleusercontent.com/EJf2u6azJe-TA6YeMWpDtMHAG6u3i1S1DhbiUXViaF5Pyg_CPEOCOEquKbX3U-drH29oYe98xKJiWqYP1ZxPGUQ545k',
bannerImage:
'https://lh3.googleusercontent.com/RAdfZt76XmM5p_rXwVsfQ3J8ca9aQUgONQaXSE1cC0bR0xETrKAoX8OEOzID-ro_3vFfgO8ZMQIqmjTiaCvuK4GtzI8',
firstName: 'First Name',
lastName: 'Last Name',
email: 'Contact Email',
bio: 'Bio will go here'
}
};
this.deleteProfile = this.deleteProfile.bind(this);
}
componentDidMount() {
const { id } = this.props.match.params;
if (this.props.profiles[id] != null) {
return;
}
this.props
.getProfile(id)
.then(() => {})
.catch(err => {
console.log(err);
});
}
createUpdatedProfile(params) {
const { id } = this.props.match.params;
const profile = this.props.profiles[id];
const { currentUser } = this.props.user;
if (currentUser.id !== profile.id) {
swal({
title: 'Oops...',
text: 'You do not own this profile',
icon: 'error'
});
return;
}
this.props
.updateProfile(currentUser, params)
.then(response => {
swal({
title: `${response.username} Updated!`,
text: 'Thank you for updating your profile',
icon: 'success'
});
})
.catch(err => {
console.log(err);
});
}
deleteProfile() {
const { id } = this.props.match.params;
const profile = this.props.profiles[id];
const { currentUser } = this.props.user;
if (currentUser.id !== profile.id) {
swal({
title: 'Oops...',
text: 'You do not own this profile',
icon: 'error'
});
return;
}
swal({
closeOnClickOutside: false,
closeOnEsc: false,
title: 'Are you sure?',
text:
'All data related to profile will be deleted as well with the profile! If you wish to delete your profile you must type DELETE',
icon: 'warning',
dangerMode: true,
buttons: true,
content: 'input'
}).then(value => {
if (value === 'DELETE') {
const userPosts = this.props.post.all.filter(p => p.profile.id === profile.id);
const userReplies = this.props.reply.all.filter(r => r.user.id === profile.id);
userPosts.map(post => {
this.props.deleteRecord(post);
});
userReplies.map(reply => {
this.props.deleteReply(reply);
});
this.props
.deleteProfile(profile)
.then(data => {
return this.props.logoutUser();
})
.then(data => {
this.props.history.push('/');
swal('Deleted!', 'Your Profile has been deleted.', 'success');
return null;
})
.catch(err => {
console.log(err);
});
}
swal({
title: 'Profile not deleted',
text: 'Make sure you type "DELETE" with caps',
icon: 'error'
});
});
}
addFriend() {
const { id } = this.props.match.params;
const profile = this.props.profiles[id];
const { currentUser } = this.props.user;
if (currentUser == null || profile == null) {
swal({
title: 'Oops...',
text: 'Must be logged in, and user must exist',
icon: 'error'
});
return;
}
const friendRequests = profile.friendRequests || [];
const params = {};
friendRequests.push(currentUser.id);
params.friendRequests = friendRequests;
this.props
.updateProfile(profile, params)
.then(() => {
swal({
title: 'Success',
text: 'Friend Request Sent',
icon: 'success'
});
})
.catch(err => {
console.log(err);
});
}
render() {
const { id } = this.props.match.params;
const profile = this.props.profiles[id];
const { currentUser } = this.props.user;
const defaultProfile = this.state.profile;
const bannerUrl =
profile == null
? defaultProfile.bannerImage
: profile.bannerImage || defaultProfile.bannerImage;
const bannerStyle = {
backgroundImage: `url(${bannerUrl})`,
backgroundSize: '100%',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center'
};
const nameStyle = {
background: 'rgba(255, 255, 255, 0.7)',
borderRadius: '8px'
};
const imageStyle = {
maxHeight: '150px',
margin: '20px auto'
};
return (
<div>
{profile == null ? (
<div>
<h1>Profile no longer exists</h1>
</div>
) : (
<div>
{currentUser == null ? null : currentUser.id !== profile.id ? null : (
<div className="list-group">
{currentUser.friendRequests
? currentUser.friendRequests.map(request => {
this.props
.getProfile(request)
.then(pendingFriend => {
console.log(pendingFriend);
return (
<div key={pendingFriend.id} className="list-group-item">
<p>{pendingFriend.username}</p>
</div>
);
})
.catch(err => {
console.log(err);
});
})
: null}
</div>
)}
<div className="jumbotron jumbotron-fluid" style={bannerStyle}>
<div className="container" style={nameStyle}>
<img
src={profile.image || defaultProfile.image}
style={imageStyle}
className="rounded img-fluid mx-auto d-block"
/>
</div>
</div>
<div className="row">
<div className="col-sm-12">
<h1 className="display-3 text-center">{profile.username}</h1>
<p className="lead text-center">
{profile.firstName || defaultProfile.firstName}{' '}
{profile.lastName || defaultProfile.lastName}
</p>
<p className="lead text-center text-muted">
{profile.email || defaultProfile.email}
</p>
<p className="text-center text-muted">
Became a User: {DateUtils.relativeTime(profile.timestamp)}
</p>
<hr className="my-4" />
<p className="lead" style={{ border: '1px solid #e6e6e6', padding: '20px' }}>
{profile.bio || defaultProfile.bio}
</p>
</div>
</div>
{currentUser == null ? null : currentUser.id !== profile.id ? (
<div className="row justify-content-center" style={{ marginBottom: '100px' }}>
<div className="col-sm-6">
{profile.friendRequests ? (
profile.friendRequests.indexOf(currentUser.id) === -1 ? (
<button
className="btn btn-primary btn-lg btn-block"
onClick={this.addFriend.bind(this)}
>
Add Friend
</button>
) : (
<button className="btn btn-success btn-lg btn-block">
Pending Friend Request
</button>
)
) : (
<button
className="btn btn-primary btn-lg btn-block"
onClick={this.addFriend.bind(this)}
>
Add Friend
</button>
)}
</div>
</div>
) : (
<div>
<UpdateProfile
currentProfile={profile}
onCreate={this.createUpdatedProfile.bind(this)}
/>
<div className="row justify-content-center" style={{ marginBottom: '100px' }}>
<div className="col-sm-6">
<button
className="btn btn-danger btn-lg btn-block"
onClick={this.deleteProfile}
>
DELETE Profile
</button>
</div>
</div>
</div>
)}
</div>
)}
</div>
);
}
}
const stateToProps = state => {
return {
profiles: state.profile,
user: state.user,
post: state.post,
reply: state.reply
};
};
const dispatchToProps = dispatch => {
return {
getProfile: id => dispatch(actions.getProfile(id)),
updateProfile: (entity, params) => dispatch(actions.updateProfile(entity, params)),
deleteProfile: entity => dispatch(actions.deleteProfile(entity)),
deleteRecord: entity => dispatch(actions.deleteRecord(entity)),
deleteReply: entity => dispatch(actions.deleteReply(entity)),
logoutUser: () => dispatch(actions.logoutUser())
};
};
const loadData = store => {
return store.dispatch(actions.getProfile(this.props.match.params.id));
};
export default {
loadData: loadData,
component: connect(stateToProps, dispatchToProps)(Profile)
};
答案 0 :(得分:1)
您的代码在很多方面打破了模式,我不知道从哪里开始:)
首先,关于无限循环的问题,你是
可能想要从render
方法中的这一行开始:
this.props.getProfile(request)
.then(pendingFriend => {
console.log(pendingFriend);
您永远不应该更新状态或派遣行动
这是重新渲染组件的两种主要方式,状态更改
和新的道具。当您发送一个实际导致的动作时
作为新道具的新渲染调用将被接收到您的连接
零件。话虽如此,不要在里面做异步调用
渲染方法,render method should be pure没有副作用。
应该在中触发异步调用和数据获取
componentDidMount
。
另一件与您的问题无直接关系的事情,大多数是你的
处理程序不是bind
类的this
对象,唯一的
你绑定的处理程序是deleteProfile
。 bind
他们全部或使用
arrow functions which will use the this
in a lexical context
同样,与您的问题没有直接关系,请始终通过props
使用constructor and super:
constructor(props) {
super(props);
修改强>
作为评论的后续内容:
如果我直接绑定像这样的函数是没关系的 this.deleteProfile.bind(this)而不是this.deleteProfile = this.deleteProfile.bind(this)在构造函数中就是这么做的 this.deleteProfile.bind(this)在render方法
中
这不会改变任何内容,因为bind
不会改变函数,而是返回一个附加this
对象的新实例(它使用{{1在幕后)你可以看到implementation
因此,您必须使用新实例覆盖处理程序
顺便说一句,在call
函数内部,进行绑定或任何其他将创建函数或对象的新实例的操作是不太可取的,因为您将在每个渲染调用上创建新实例。如果你可以&#34;提升&#34;它取决于像render
这样的方法(在组件的生命周期中只调用一次)效率更高。