i am using react redux. In this Profiles component i use this.startSetUsers in componentWillMount to trigger fetching users from the mongodb and store it to state. then i mapStateToProps to get users from state as props, so i get this.props.users. Then in render i try to pass users as props to ProfilesList component and render that or if no users render no users from Profile component.
Now this works if state is empty and i navigate to ProfilesList or if i refresh that particular url with ProfilesList component but if go to ProfilePage component where through startSetUser i get only one user in state and show it in ProfilePage and then from that component where now state has one user i try to go to ProfilesList via < Link> show all users < /Link> i get an error "this.props.users.map is not a function" and i guess that is because mapStateToProps isnt finished before rendering and using this.props.users.map
i hope someone understood me, this was a bit mouthful. :D is there some work around this?
class Profiles extends React.Component {
componentWillMount() {
this.props.startSetUsers()
}
render() {
return(
<div className="content-container content-container--list">
<div className="list-header">
<div className="show-for-mobile">Users</div>
<div className="show-for-desktop">User</div>
<div className="show-for-desktop">Joined</div>
</div>
<div className="list-body">
{this.props.users.length === 0 ? (
<div className="list-item list-item--message">
<span>No users</span>
</div>
) : (
this.props.users.map((user) => {
return <ProfilesList key={user._id} {...user} />
})
)
}
</div>
</div>
)
}
}
const mapStateToProps = (state) => ({
users: state.user
})
export default connect(mapStateToProps, actions)(Profiles)
ProfilesList
const ProfilesList = ({ username, email, created_at, avatar }) => (
<Link className="list-item" to={`/user/${username}`}>
<div className="list-item__avatar-title">
<div className="list-item__avatar">
<img src={avatar || 'https://image.ibb.co/bUv8k7/NoImage.png'} />
</div>
<div>
<h3 className="list-item__title">{username}</h3>
<span className="list-item__sub-title">{email}</span>
<br />
<span className="list-item__sub-title">List of articles: X</span>
</div>
</div>
<div>
<h4 className="list-item__joined">{moment(created_at).format('MMMM Do, YYYY')}</h4>
</div>
</Link>
)
export default ProfilesList;
Profile
class Profile extends React.Component {
constructor(props) {
super(props);
this.state = {
usersLoaded: false
};
}
componentWillMount() {
this.props.startSetUser(this.props.match.params.id)
}
render() {
return(
<div>
{
this.props.user && this.props.match.params.id ?
<ProfilePage {...this.props}/> :
<div>404</div>
}
</div>
)
}
}
const mapStateToProps = (state, props) => ({
user: state.user
})
export default connect(mapStateToProps, actions)(Profile)
ProfilePage
const ProfilePage = props => {
const {user} = props;
return (
<div className="section">
<div className="profile__header">
<div className="profile__name">
<h2>{`${user.firstName} ${user.lastName}`}</h2>
<h3>{user.email}</h3>
</div>
</div>
<div className="profile__content">
<div className="photo-container">
<div className="photo">
<img src={user.avatar || 'https://image.ibb.co/bUv8k7/NoImage.png'} />
</div>
</div>
<div className="profile__info">
<p>Username: <strong>{user.username}</strong></p>
<li>Email: <strong>{user.email}</strong></li>
<li>Location: <strong>{user.location}</strong></li>
<li>City: <strong>{user.city || renderMessage}</strong></li>
<li>Birthday: <strong>{`${user.day} ${user.month}, ${user.year}`}</strong></li>
<li>Gender: <strong>{user.gender}</strong></li>
<li>Joined: <strong>{moment(user.created_at).format('MMMM Do, YYYY')}</strong></li>
</div>
<div className="profile__button">
<button className="button">Edit</button>
<Link to="/users" className="button">List of all users</Link>
</div>
</div>
</div>
);
};
export default ProfilePage;
reducer
const userReducer = (state = [], action) => {
switch (action.type) {
case 'SET_USER':
return action.user;
case 'SET_USERS':
return action.users;
default:
return state;
}
};
export default userReducer;
edit: forgot to post action
// SET_USER
export const setUser = (user) => ({
type: 'SET_USER',
user
})
export const startSetUser = (username) => {
return (dispatch) => {
axios.get(`${ROOT_URL}/user/${username}`)
.then(response => {
dispatch(setUser(response.data))
})
}
}
// SET_USERS ALL
export const setUsers = (users) => ({
type: 'SET_USERS',
users
})
export const startSetUsers = () => {
return (dispatch) => {
axios.get(`${ROOT_URL}/users`)
.then(response => {
dispatch(setUsers(response.data))
})
}
}