Create the User file under user folder.
user/Users.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import React, { Component } from "react"; import { getUserList } from "./apiUser"; import DefaultProfile from '../images/default-profile.png'; import { Link } from 'react-router-dom'; class Users extends Component { constructor() { super() this.state = { users: [] } } componentDidMount() { getUserList().then(data => { if (data.error) { console.log(data.error) } else { this.setState({users:data}) } }) } renderUsers = users => ( <div className="row"> {users.map((user, i) => ( <div className="card col-md-4" key={user._id}> <img className="card-img-top" src={DefaultProfile} alt={user.name} style={{width: '100%', height: '15vw', objectFit: 'cover' }} /> <div className="card-body"> <h5 className="card-title">{user.name}</h5> <p className="card-text">{user.email}</p> <Link to={`/user/${user._id}`} className="btn btn-primary">View Profile </Link> </div> </div> ))} </div> ); render() { const { users } = this.state return ( <div className="container"> <h2 className="mt-5 mb-5"> Users </h2> {this.renderUsers(users)} </div> ); } } export default Users; |
The result is a list of users.
Props Change on Users
1) Go the users list http://localhost:3000/users
2) Click on View Profile link of any user. You’ll get to the profile page of that user with that user’s data.
3) If you were to click on your own profile link above, the component data wouldn’t change. This is because the URL is part of prop. Since you’ve changed the URL, you’re changing the prop. This change happens at this.props.match.params.userId.
This is the props of the component and when it changes, we need to fetch data for the profile user again. However, in our Profile component, we only do this for when componentDidMount. Thus, we need to implement fetch data in a component hook called componentDidUpdate like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class Profile extends Component { // etc componentDidMount() { const userId = this.props.match.params.userId this.initUserID(userId) } // componentWillReceiveProps is required if you want to update the state values with new props values, // this method will get called whenever any change happens to props values. // However, "componentWillReceiveProps()" has been deprecated. // You should use, "componentDidUpdate(prevProps, prevState, snapshot)". //https://stackoverflow.com/questions/46113044/when-to-use-componentwillreceiveprops-lifecycle-method?r=SearchResults //https://reactjs.org/docs/react-component.html#componentdidupdate componentDidUpdate(prevProps) { // Typical usage (don't forget to compare props): if (this.props.match.params.userId !== prevProps.match.params.userId) { console.log('user/Profile.js', 'componentDidUpdate'); const userId = this.props.match.params.userId this.initUserID(userId) } } // other code } |
user/Profile.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
import React, { Component } from 'react'; import { IsAuthenticated } from '../auth'; import { Redirect, Link} from 'react-router-dom'; import { getUserInfo } from './apiUser'; import DefaultProfile from '../images/default-profile.png' class Profile extends Component { constructor() { super() this.state = { user: "", redirectToSignin: false } } initUserID = userId => { let token = IsAuthenticated().token console.log('0) get user info') getUserInfo(userId, token) .then(data => { console.log('4) callback for logging and presentation') if (data.error) { this.setState({ redirectToSignin: true }) } else { this.setState({ user: data }) } }) console.log('2) finish him!!!') } componentDidMount() { console.log('user/Profile.js', 'componentDidMount'); const userId = this.props.match.params.userId this.initUserID(userId) } // componentWillReceiveProps is required if you want to update the state values with new props values, // this method will get called whenever any change happens to props values. // However, "componentWillReceiveProps()" has been deprecated. // You should use, "componentDidUpdate(prevProps, prevState, snapshot)". //https://stackoverflow.com/questions/46113044/when-to-use-componentwillreceiveprops-lifecycle-method?r=SearchResults //https://reactjs.org/docs/react-component.html#componentdidupdate componentDidUpdate(prevProps) { // Typical usage (don't forget to compare props): if (this.props.match.params.userId !== prevProps.match.params.userId) { console.log('user/Profile.js', 'componentDidUpdate'); const userId = this.props.match.params.userId this.initUserID(userId) } } // when route parameter changes, we need to capture that change // make another fetch request so that our data can be updated // current when componet mounts, it fetches that time. render() { const { user, redirectToSignin } = this.state if (redirectToSignin) return <Redirect to="/signin" /> return ( <div className="container"> <div cl assName="row"> <div className="col-md-6"> <h2 className="mt-5 mb-5">Profile</h2> <img className="card-img-top" src={DefaultProfile} alt={user.name} style={{width: '100%', height: '15vw', objectFit: 'cover' }} /> <ul> <li>Hi, {user.name}</li> <li>{user._id}</li> <li>{user.email}</li> <li>{user.created && `Joined on ${new Date(user.created).toDateString()}`}</li> </ul> </div> <div className="col-md-6"> {/* if the authenticated user is same as getUserInfo's id */} {IsAuthenticated().user && IsAuthenticated().user._id === user._id && (<div className="d-line-block mt-5"> <Link className="btn btn-raised btn-success mr-5" to={`/user/edit/${user._id}`}> Edit Profile </Link> <button className="btn btn-raised btn-danger" to={`/user/delete/${user._id}`}> Delete Profile </button> </div>) } </div> </div> </div> ); } } export default Profile |