How to update data to a reactjs website?

Hi everyone,

In my mongodb compass I can see my user table with “About Me” and other info. Then I added a “Phone number” info just below “About Me” in my reactjs code. I run my reactjs website and could type my phone number in the Edit page. Then, I clicked a submit button but the website failed to show my phone number in the updated page. I tried to add “Phone” below the “AboutMe” in my mongodb compass database name code editor but it still can’t insert “Phone” on my reactjs website. Can you show me a step by step screenshot about how to add a “Phone” info on to my reactjs website and by how, mongodb compass or which way? Thank you.

Hi Jen - Welcome to the community!

Were you able to get this solved? If not, you might find this example helpful: https://www.mongodb.com/blog/post/the-modern-application-stack-part-5-using-reactjs-es6-and-jsx-to-build-a-ui-the-rise-of-mern

Hi Lauren,
No. But I have another question. Here is a screenshot of the Edit Profile page. At first, there is no ‘Phone number’ in the Edit Profile Page, but I have just added ‘Phone number’ in the Edit Profile page.

When I click on the Edit Profile button in the Profile Page, I can update info like ‘About Me’, ‘Password’ and also ‘Phone number’ which can also show the updated changes in my mongodb database. I simply entered my phone number in alphabets since I chose the phone number type to be of a string in my react code for me to just try out if the phone number could show anything but I will change it to numbers later. But the ‘Phone number’ failed to display on the main Profile page here=
image

When I run the website as npm start=
Starting the development server…
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Should I run the above command?

It is also compiled with warnings. Can I ignore the warnings below?=
File1.js
Duplicate key ‘background’ no-dupe-keys

File2.js
‘React’ is defined but never used no-unused-vars

File3.js
Duplicate key ‘background’ no-dupe-keys

Thank you!

A typo in my earlier post because it is the same question and not another question.

Hi Jen,

I don’t know React, but I can take some guesses about the warnings.

In File1 and File3, are you setting background twice on the same object? https://eslint.org/docs/rules/no-dupe-keys has some information on this warning.

In File2, it sounds like you are declaring a variable named React but not using it. https://eslint.org/docs/rules/no-unused-vars has some information on this warning.

Regarding the phone number issue. I think what you’re saying is…

  1. You can input information in the About Me and Phone Number fields
  2. You can see that information in your MongoDB database
  3. The About Me information is displayed on the page but the Phone Number is not.

Is that right?

Can you double check that the name of your phone number field in MongoDB exactly matches the name you’re using to retrieve the field in your code? It’d be helpful to see the document in your database as well as the code you’re using to retrieve the information from your database.

Hi Lauren,

There are no errors after I renamed the background in line 2 to background1 and background in line 3 to background2. Am I right for these?=

style={{
   background: "#dcdcdc",
   background: "-webkit-linear-gradient(to left, #dcdcdc, #ee82ee
)",
   background: "linear-gradient(to left, #dcdcdc, #ee82ee
)",
}}

What is wrong with File 2?=

import React, { Component } from "react";
import { withRouter } from "react-router-dom";

class ScrollToTop extends Component {
    componentDidUpdate(prevProps) {
        if (this.props.location !== prevProps.location) {
            window.scrollTo(0, 0);
        }
    }

    render() {
        return(
            this.props.children
        ); 
    }
}

export default withRouter(ScrollToTop)

Yes, that is right. Both match.

Do I show you the codes in my 3 files here or do I email you these?

Thank you!

Hi Jen,

https://eslint.org/docs/rules/no-dupe-keys says “Multiple properties with the same key in object literals can cause unexpected behavior in your application.” Try setting the background only to the value you want to use.

For File2, you are importing React, but it sounds like you aren’t using it. You can probably remove the import.

Paste your document and code here so that everyone can benefit from the discussion.

Hi Lauren,

I removed ‘background: “#dcdcdc”,’ in line 1 for the code but the error still shows that points to background in line 3. I don’t know which one is important for me to keep. Should I remove background in line 3 or in line 2?=

style={{
   background: “#dcdcdc”,
   background: “-webkit-linear-gradient(to left, #dcdcdc, #ee82ee
)”,
   background: “linear-gradient(to left, #dcdcdc, #ee82ee
)”,
}}

Do I remove both import React, { Component } from “react”; & import { withRouter } from “react-router-dom”;?

Here is my MongoDB Compass database=
image

User.js=

const mongoose = require('mongoose');
const { v1: uuidv1 } = require('uuid');
const crypto = require('crypto');
const { ObjectId } = mongoose.Schema;


const userSchema = new mongoose.Schema({
    name: {
        type: String,
        trim: true,
        required: true
    },
    email: {
        type: String,
        trim: true,
        required: true
    },
    hashed_password: {
        type: String,
        required: true
    },
    salt: String,
    created: {
        type: Date,
        default: Date.now
    },
    updated: Date,
    photo: {
        data: Buffer,
        contentType: String
    },
    about: {
        type: String,
        trim: true  
    },
    phone: {
        type: String,
        trim: true
    },
    notificationToken: {
        type: String
    },
    following: [{
        type: ObjectId,
        ref: "User"
    }],
    followers: [{
        type: ObjectId,
        ref: "User"
    }],
    resetPasswordLink: {
        data: String,
        default: ""
    }

});

//virtual field
userSchema.virtual('password')
.set(function(password){
    //create temp var _password
    this._password = password;
    //generate a timestamp
    this.salt = uuidv1();
    // encrypt password
    this.hashed_password = this.encryptPassword(password);
})
.get(function(){
    return this._password;
})


//methods
userSchema.methods = {

    authenticate: function(plainText){
        return this.encryptPassword(plainText) === this.hashed_password;
    },

    encryptPassword: function(password){
        if(!password) return "";
        try{
            return crypto.createHmac('sha1',this.salt)
                    .update(password)
                    .digest('hex')
        } catch(err){
            return ""
        }
    }
}
module.exports = mongoose.model("User", userSchema);

Profile.js=
import React, { Component } from 'react';

import { isAuthenticated } from "../auth";
import { Redirect, Link } from 'react-router-dom';
import { read } from "./apiUser";
import DefaultProfile from '../images/avatar.jpg';
import DeleteUser from './DeleteUser';
import FollowProfileButton from './FollowProfileButton';
import { listByUser } from '../post/apiPost';
import '../css/Profile.css';

import { Tabs, Tab } from 'react-bootstrap-tabs';

import Loading from '../loading/Loading';

class Profile extends Component {
    constructor() {
        super();
        this.state = {
            // user: "",
            user: { following: [], followers: [] },
            redirectToSignin: false,
            following: false,
            error: "",
            posts: [],
            loading: false
        }
    }

    // check follow
    checkFollow = (user) => {
        const jwt = isAuthenticated();
        const match = user.followers.find(follower => {
            return follower._id === jwt.user._id
        })
        return match
    }


    clickFollowButton = callApi => {
        this.setState({ loading: true })
        const userId = isAuthenticated().user._id;
        const token = isAuthenticated().token;
        callApi(userId, token, this.state.user._id)
            .then(data => {
                if (data.error) {
                    
                    this.setState({ error: data.error })
                } else {
                    this.setState({ user: data, following: !this.state.following, loading: false })
                }
            })
    }

    // profileUnfollow = (unfollowId) => {
    //     const userId = isAuthenticated().user._id;
    //     const token = isAuthenticated().token;
    //     unfollow(userId, token, unfollowId)
    //     .then(data => {
    //         if (data.error) {
    //             this.setState({ error: data.error })
    //         } else {
    //             this.setState({ user: data })
    //         }
    //     })
    // }

    // unfollowClick = (e) => {
    //     const unfollowId = e.target.getAttribute("data-index");
    //     this.profileUnfollow(unfollowId);
    // }

    init = (userId) => {
        this.setState({ loading: true })
        const token = isAuthenticated().token;
        read(userId, token)
            .then(data => {
                if (data.error) {
                    this.setState({ redirectToSignin: true });
                } else {
                    let following = this.checkFollow(data);
                    this.setState({ user: data, following });
                    this.loadPosts(data._id);
                }
            });
    };

    loadPosts = (userId) => {
        const token = isAuthenticated().token;
        listByUser(userId, token)
            .then(data => {
                if (data.error) {
                    console.log(data.error)
                } else {
                    this.setState({ posts: data, loading: false });
                }
            })
    }

    componentDidMount() {
        const userId = this.props.match.params.userId;
        this.init(userId);
    }

    componentWillReceiveProps(props) {
        const userId = props.match.params.userId;
        this.init(userId);
    }

    renderProfile = () => {
        const { user, following, posts } = this.state;
        const photoUrl = user._id ? `${process.env.REACT_APP_API_URL}/user/photo/${user._id}?${new Date().getTime()}` : DefaultProfile;
        let followingBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-primary">{user.following.length}</span> Following</p>
        let followersBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-success">{user.followers.length}</span> Followers</p>
        let postsBadge = <p style={{ marginBottom: "0" }}><span className="badge badge-pill badge-warning">{posts.length}</span> Posts</p>
        return <div className="user-profile">
            <div className="row">
                <div className="col-md-4">
                    <div className="profile-info-left">
                        <div className="text-center">
                            <img 
                                height="300"
                                width="300"
                                src={photoUrl} 
                                alt={user.name} 
                                onError={i => (i.target.src = DefaultProfile)} 
                                className="avatar img-circle" 
                            />
                            <h2 className="mt-2" >{user.name}</h2>
                        </div>
                        <div className="action-buttons">
                            {isAuthenticated().user && isAuthenticated().user._id === user._id ? (
                                <>
                                <div className="row">
                                    <div className="col-md-4 col-xs-6">
                                        <Link 
                                            className="btn btn-sm btn-raised btn-primary"
                                            to={`/post/create`}
                                        >
                                            Create Post
                                        </Link>
                                    </div>
                                    <div className="col-md-4 col-xs-6">
                                        <Link 
                                        className="btn btn-sm btn-raised btn-dark"
                                            to={`/user/edit/${user._id}`}
                                        >
                                            Edit Profile
                                        </Link>
                                    </div>

                                </div>
                                <div className="mt-2">
                                    <DeleteUser userId={user._id} />
                                </div>
                                </>
                            ): (
                                <div className="row">
                                    <div className="col-md-6 col-xs-6">
                                        <Link 
                                            className="btn btn-sm btn-raised btn-success ml-3"
                                            to={`/chat/${isAuthenticated().user._id}/${user._id}`}
                                        >
                                            Message
                                        </Link>
                                    </div>
                                    <div className="col-md-6 col-xs-6">
                                        <FollowProfileButton following={following} onButtonClick={this.clickFollowButton} />
                                    </div>
                                </div>                                            
                            )}
                            
                        </div>
                        <div className="section">
                            <h3>About Me</h3>
                            <p>{user.about}</p>
                        </div>
                        <div className="section">
                            <h3>Phone Number</h3>
                            <p>{user.phone}</p>
                        </div>
                        <div className="section">
                            <h3>Statistics</h3>
                            <p><span className="badge badge-pill badge-primary">{user.following.length}</span> Following</p>
                            <p><span className="badge badge-pill badge-success">{user.followers.length}</span> Followers</p>
                            <p><span className="badge badge-pill badge-warning">{posts.length}</span> Posts</p>
                        </div>
                    </div>
                </div>
                <div className="col-md-8">
                    <div className="profile-info-right">
                        <Tabs onSelect={(index, label) => console.log(label + ' selected')}>
                            <Tab label={postsBadge} className="tab-title-name">
                                <div className="row">
                                {posts.map((post, i) => (
                                    <div key={i} style={{ paddingBottom: "15px" }} className="col-md-4">
                                        <Link to={`/post/${post._id}`} >
                                            <figure className="snip1205 red">
                                                <img 
                                                    style={{ objectFit: "cover", padding: "0" }}
                                                    height="200"
                                                    width="200"
                                                    src={`${process.env.REACT_APP_API_URL}/post/photo/${post._id}`}
                                                    alt={post.title} 
                                                />
                                                <i className="fas fa-heart">
                                                    <br />
                                                    <span style={{ color: "white", fontSize: "20px" }} >{post.likes.length}</span>
                                                </i>
                                            </figure>
                                        </Link>
                                    </div>
                                ))}
                                </div>
                            </Tab>
                            <Tab label={followersBadge}  className="tab-title-name">
                                {user.followers.map((person, i) => (
                                    <div key={i} className="media user-follower">
                                        <img 
                                            src={`${process.env.REACT_APP_API_URL}/user/photo/${person._id}`}
                                            onError={i => (i.target.src = DefaultProfile)}
                                            alt={person.name} 
                                            className="media-object pull-left mr-2" 
                                        />
                                        <div className="media-body">
                                            <Link to={`/user/${person._id}`} >
                                                {person.name}<br /><span className="text-muted username">@{person.name}</span>
                                            </Link>
                                            {/* <button type="button" className="btn btn-sm btn-toggle-following pull-right"><i className="fa fa-checkmark-round"></i> <span>Following</span></button> */}
                                        </div>
                                    </div>
                                ))}
                            </Tab>

                            <Tab label={followingBadge} className="tab-title-name">
                                {user.following.map((person, i) => (
                                    <div key={i} className="media user-following">
                                        <img 
                                            src={`${process.env.REACT_APP_API_URL}/user/photo/${person._id}`}
                                            onError={i => (i.target.src = DefaultProfile)}
                                            alt={person.name} 
                                            className="media-object pull-left mr-2" 
                                        />
                                        <div className="media-body">
                                            <Link to={`/user/${person._id}`} >
                                                { person.name }<br /><span className="text-muted username">@{person.name}</span>
                                            </Link>
                                            {/* <button data-index = {person._id} onClick={this.unfollowClick} type="button" className="btn btn-sm btn-toggle-following pull-right"><i className="fa fa-checkmark-round"></i> <span>Unfollow</span></button> */}
                                        </div>
                                    </div>
                                ))}
                            </Tab>
                        </Tabs>
                    </div>
                </div>
            </div>
        </div>
    }


    render() {
        const { redirectToSignin, user, loading } = this.state;
        console.log("state user", user);
        if (redirectToSignin) {
            return <Redirect to='/signin' />
        }


        return (
            <div className="container">
                { loading ? (
                    <Loading />
                ) : (
                    this.renderProfile()
                ) }
            </div>
        );
    }
}

export default Profile;

EditProfile.js=

import React, { Component } from 'react';

import Loading from '../loading/Loading';

import { read, update, updateUser } from "./apiUser";
import { isAuthenticated } from "../auth";
import { Redirect } from 'react-router-dom';
import DefaultProfile from '../images/avatar.jpg';


class EditProfle extends Component {

    constructor() {
        super();
        this.state = {
            id: "",
            name: "",
            email: "",
            about: "",
            phone: "",
            password: "",
            loading: false,
            redirectToProfile: false,
            error: "",
            fileSize: 0
        }
    }

    init = (userId) => {
        const token = isAuthenticated().token;
        read(userId, token)
            .then(data => {
                if (data.error) {
                    this.setState({ redirectToProfile: true })
                } else {
                    this.setState({ 
                        id: data._id,
                        name: data.name,
                        email: data.email,
                        error: "" ,
                        about: data.about,
                        phone: data.phone
                    });
                }
            })
    }

    componentDidMount() {
        this.userData = new FormData()
        const userId = this.props.match.params.userId;
        this.init(userId);
    }

    isValid = () => {
        const { name, email, password, fileSize } = this.state;
        const userId = this.props.match.params.userId;
        if(userId !== isAuthenticated().user._id){
            this.setState({ error: "You are not authorized to do this !!", loading: false });
            return false;
        }

        if (fileSize > 1000000) {
            this.setState({ error: "File size should be less than 1 MB", loading: false });
            return false;
        }

        if (name.length === 0) {
            this.setState({ error: "Name is required", loading: false });
            return false;
        }
        //test regular expression with 'test' keyword
        if (!/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
            this.setState({ error: "Please enter a valid email address.", loading: false });
            return false;
        }
        if (password.length >= 1 && password.length <= 5) {
            this.setState({ error: "Password must be at least 6 characters long", loading: false });
            return false;
        }
        return true;
    }

    handleChange = e => {
        const value = e.target.name === 'photo' ? e.target.files[0] : e.target.value;
        const fileSize = e.target.name === 'photo' ? e.target.files[0].size : 0;
        this.userData.set(e.target.name, value);
        this.setState({
            error: "",
            [e.target.name]: value,
            fileSize
        });
    };

    clickSubmit = e => {
        e.preventDefault();
        this.setState({ loading: true })
        if (this.isValid()) {
            //const { name, email, password } = this.state;
            //const user = { name, email, password: password || undefined };
            // console.log(user);
            const userId = this.props.match.params.userId;
            const token = isAuthenticated().token;
            update(userId, token, this.userData)
                .then(data => {
                    if (data.error) {
                        this.setState({ error: data.error, loading: false });
                    } else {
                        updateUser(data, () => {    
                            this.setState({
                                redirectToProfile: true
                            });
                        })
                    }
                });
        }

    };

    signupForm = (name, email, password, loading, about, phone) => (
        <form>
            <div className="form-group">
                <label className="text-muted">Profile Photo</label>
                <input
                    onChange={this.handleChange}
                    name="photo"
                    type="file"
                    accept="image/*"
                    className="form-control"
                />
            </div>
            <div className="form-group">
                <label className="text-muted">Name</label>
                <input
                    onChange={this.handleChange}
                    name="name"
                    type="text"
                    className="form-control"
                    value={name}
                />
            </div>
            <div className="form-group">
                <label className="text-muted">Email</label>
                <input
                    onChange={this.handleChange}
                    type="email"
                    name="email"
                    className="form-control"
                    value={email}
                />
            </div>
            <div className="form-group">
                <label className="text-muted">About</label>
                <textarea
                    onChange={this.handleChange}
                    type="text"
                    name="about"
                    className="form-control"
                    value={about}
                />
            </div>
            <div className="form-group">
                <label className="text-muted">Phone</label>
                <textarea
                    onChange={this.handleChange}
                    type="string"
                    name="phone"
                    className="form-control"
                    value={phone}
                />
            </div>
            <div className="form-group">
                <label className="text-muted">Password</label>
                <input
                    onChange={this.handleChange}
                    type="password"
                    name="password"
                    className="form-control"
                    value={password}
                />
            </div>
            
            <button onClick={this.clickSubmit} className="btn btn-raised btn-primary">Update</button>
        </form>
    );

    render() {

        const { id, name, email, password, loading, redirectToProfile, error, about, phone } = this.state;
        if (redirectToProfile) {
            return <Redirect to={`/user/${isAuthenticated().user._id}`}></Redirect>
        }
        const photoUrl = id ? `${process.env.REACT_APP_API_URL}/user/photo/${id}?${new Date().getTime()}` : DefaultProfile ;

        return (
            <div className="container">
                <h2 className="mt-5 mb-5">Edit Profile</h2>
                <div className="alert alert-danger" style={{ display: error ? "" : "none" }}>
                    {error}
                </div>
                <img 
                    style={{ display: loading ? "none" : "" , height: "200px", width: "auto" }} 
                    className="img-thumbnail" 
                    src={photoUrl} 
                    onError={i => (i.target.src = DefaultProfile)}
                    alt={name} 
                />
                {loading ? (
                    <Loading />
                ) : (
                    this.signupForm(name, email, password, loading, about, phone)
                )}
            </div>
        );
    }
}

export default EditProfle;

Thank you!

Hi Jen,

A couple of things…

  1. I’m not sure which background you want to keep. I’m not sure what the difference between webkit-linear-gradient and linear-gradient is. You might want to google those. Or just try and see what happens in a couple of different browsers.
  2. Without really digging into your code, I’m not sure what imports you’re using. You could try just removing the React import: import { Component } from “react”;. I think these are just warnings though that can be ignored if you don’t want to clean up your imports.
  3. I perused the differences between about and phone. Looks like your form-group for about has type="text" and your form-group for phone has type="string". Not sure if that could be causing the problem.
  4. Are you getting any errors displayed in your browser’s console?
  5. Can you take a look at the formatting of your comment above? It’s hard to tell where files begin and end.

Hi Lauren,

  1. I will later google and try these in different browsers. Will this also cause the problem of
    updating a phone number?
  2. The phone number still can’t be displayed on my profile page after I changed type=“text”
    for phone.
  3. Yes, the errors are=
index.js:1 Warning: Using UNSAFE_componentWillReceiveProps in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-unsafe-component-lifecycles for details.

* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state

Please update the following components: InfiniteScroll
console.<computed> @ index.js:1

Profile.js:263 state user Object
index.js:1 Warning: Failed prop type: Invalid prop `label` of type `object` supplied to `TabComponent`, expected `string`.
    in TabComponent (at Profile.js:193)
    in Profile (at PrivateRoute.js:7)
    in Route (at PrivateRoute.js:6)
    in PrivateRoute (at MainRouter.js:35)
    in Switch (at MainRouter.js:25)
    in div (at MainRouter.js:23)
    in MainRouter (at App.js:9)
    in ScrollToTop (created by Context.Consumer)
    in withRouter(ScrollToTop) (at App.js:8)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:7)
    in App (at src/index.js:7)
    in StrictMode (at src/index.js:6)
console.<computed> @ index.js:1
Profile.js:263 state user Object
react-dom.development.js:88 Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.

* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

Please update the following components: Profile, TabsComponent
printWarning @ react-dom.development.js:88
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object
Profile.js:263 state user Object 

Do you also want to see each dropdown list of errors for each Profile.js above?

  1. What did you mean? Please clarify.

Thank you!

Hi Jen,

The background color thing should not be impacting the phone number.

I recommend diving into the Profile.js errors. What is happening on line 263? What is happening in index.js on or around line 1?

Hi Lauren,

It displays a user info for line 263 for Profile.js= console.log(“state user”, user);?

I have 2 index.js files. Which one to refer to? One file starts from line 1 and other file starts from line 3. If you mean the other file, it is fetching the sign up info.

Thanks!

Ah, ok, so the Profile logging is just a log and not an error.

I’m not sure which index.js is being access on that page. See if you can do some debugging. I’m guessing the problem is related to the warning being shown:
index.js:1 Warning: Failed prop type: Invalid prop label of type object supplied to TabComponent, expected string.

Hi Lauren,

I found the right index.js and I guess there is no import React from ‘react’; or etc on line 1 but it simply begins with export const signup = (user) => {. Must it import something on line 1, for example import PropTypes from ‘prop-types’;

Component.propTypes = {? Or how should the import line of code be like?

Thank you!

Hi Lauren,
When can you help me to debug the phone error code?
Thanks!

Hi Jen,
Have you figured out the source of this warning?

index.js:1 Warning: Failed prop type: Invalid prop label of type object supplied to TabComponent , expected string .

I’m wondering if that is what is causing the problems.

Hi Lauren,

I searched for Tab and the problem related files Profile.css, Profile.js. and chat.js

Thank you!

Were you able to figure it out?

No, I weren’t. Can you figure it out for me? Thanks, Lauren!

Looking at the stack trace, it looks like the error is occurring in TabComponent (at Profile.js:193). Have you checked there?