Related
1.After I came to profile page that show my profile details my console log shows POST http://localhost:3000/profileEdit 500 (Internal Server error)
2.I change my activity drinks about topics and then refresh page it shows nothing like it didn't save at all except image
I debug by myself then tried to find solution in reddit, quora, stackoverflow 5 day but can't find it So please could you help me a bit
this is frontend
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { useCookies } from "react-cookie";
import { Link } from "react-router-dom";
import axios from "axios";
import {
ref, uploadBytesResumable, getDownloadURL, getStorage
} from "firebase/storage";
import { profileInit } from "../redux/action";
import "./profileEdit.css";
import styled from "styled-components";
const Avatar = styled.div`
width: 250px;
height: 250px;
border-radius: 50%;
background-size: cover;
background-position: center;
cursor: pointer;
`;
function ProfileEdit(props) {
const [cookies, removeCookies] = useCookies([
"userName",
"userNickname",
]);
const [activity, setActivity] = useState("");
const [drinks, setDrinks] = useState("");
const [topics, setTopics] = useState("");
const [about, setAbout] = useState("");
const [url, setUrl] = useState("./images/UploadPic.svg");
const [save, setSave] = useState("");
const id = cookies.userName;
const { profileInit, user } = props;
const [image, setImage] = useState(null);
function patchData(event) {
event.preventDefault();
axios
.patch("/users/profile", {
activity,
drinks,
topics,
about,
id,
})
.then(({ data }) => {
if (data.success) {
setSave("Changes were saved");
} else {
setSave(data.err);
}
});
const storage = getStorage();
const storageRef = ref(storage, `images/${cookies.userName || "./images/infoUser.svg"}`);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on("state_changed", undefined, undefined, () => {
getDownloadURL(storageRef).then((url) => {
setUrl(url);
});
});
if (setUrl !== null || setUrl == null) {
axios
.patch("/users/profile", {
activity,
drinks,
topics,
about,
id,
avatar: url,
})
.then(({ data }) => {
if (data.success) {
setSave("Saved");
} else {
setSave(data.err);
}
});
}
}
function handleChangeAbout(event) {
event.preventDefault();
setAbout(event.target.value);
}
function handleChangeDrinks(event) {
event.preventDefault();
setDrinks(event.target.value);
}
function handleChangeTopics(event) {
event.preventDefault();
setTopics(event.target.value);
}
function handleChangeActivity(event) {
event.preventDefault();
setActivity(event.target.value);
}
function LogOut() {
user.id = null;
removeCookies("userName");
removeCookies("userNickname");
}
useEffect(() => {
const storage = getStorage();
getDownloadURL(ref(storage, `images/${cookies.userName}`))
.then((url) => {
setUrl(url);
});
axios
.post('/users/profileEdit', {
id,
})
.then(({ data }) => {
setActivity(data.profileId.activity);
setDrinks(data.profileId.drinks);
setAbout(data.profileId.about);
setTopics(data.profileId.topics);
profileInit(data.profileId);
});
}, [profileInit, id]);
function photoDownload(e) {
if (e.target.files[0]) {
setImage(e.target.files[0]);
const storage = getStorage();
const storageRef = ref(storage, `images/${cookies.userName}`);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on(
"state_changed",
() => {
setUrl("./loading.gif");
},
(error) => {
console.log(error);
},
() => {
getDownloadURL(storageRef)
.then((url) => {
setUrl(url);
});
},
);
}
}
return (
<>
<div className="profile-container">
<div style={{ alignSelf: "center" }}>
<label htmlFor="file-input">
<Avatar style={{ backgroundImage: `url(${url})` }} />
</label>
<input id="file-input" type="file" onChange={photoDownload} />
</div>
<form onSubmit={patchData} className="edit">
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Activity:
</span>
<label>
<input
value={activity}
onChange={handleChangeActivity}
type="text"
name="activity"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Topics:
</span>
<label>
<input
value={topics}
onChange={handleChangeTopics}
type="text"
name="topics"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
About:
</span>
<label>
<input
value={about}
onChange={handleChangeAbout}
type="text"
name="about"
className="profileInput"
required
/>
</label>
<span
style={{ textShadow: "none", marginBottom: "8px", color: "#fff" }}
>
Drinks:
</span>
<label>
<input
value={drinks}
onChange={handleChangeDrinks}
type="text"
name="drinks"
className="profileInput"
required
/>
</label>
<button
style={{ margin: "0 auto" }}
className="chatButton"
>
{" "}
Save changes
{" "}
</button>
<div style={{ marginTop: "15px", color: "#fff" }}>
{" "}
{save}
</div>
</form>
<div className="quitEdit" style={{ margin: "0 auto" }}>
<Link to="/listUsers" style={{ position: "relative" }}>
<img src="./images/back.svg" width="100" height="100" alt="BackToListPage" title="BackToListPage" />
</Link>
</div>
<div className="exit" style={{ margin: "0 auto" }}>
<Link to="/login" onClick={LogOut} style={{ position: "relative" }}>
<img src="./images/exit.svg" width="100" height="100" alt="Logout" title="Logout" />
</Link>
</div>
</div>
</>
);
}
const mapStateToProps = (state) => ({
profileId: state.user.profileId,
user: state.user,
err: state.error,
});
const mapDispatchToProps = (dispatch) => ({
profileInit: (profileId) => dispatch(profileInit(profileId)),
});
export default connect(mapStateToProps, mapDispatchToProps)(ProfileEdit);
my backend code for /users/profile and /users/profileEdit
router.patch('/profile', async (req, res) => {
const {
activity,
topics,
about,
drinks,
avatar,
id,
} = req.body;
const response = await Profile.updateOne({ person: id }, {
activity, topics, about, drinks, avatar
});
if (response) {
res.send({ success: true });
} else {
res.send({ success: false, err: 'Try again' });
}
});
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ profileId: response });
} else {
res.status(500).send({ err: 'Something went wrong' });
}
});
Edit post here -> modelProfile.js
const mongoose = require('mongoose');
const profileSchema = new mongoose.Schema({
person: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Person',
},
name: {
type: String,
required: true,
minlength: 1,
},
DoB: {
type: Date,
required: true,
},
activity: {
type: String,
required: true,
minlength: 1,
},
about: {
type: String,
minlength: 1,
},
topics: String,
drinks: String,
avatar: String,
latitude: Number,
longitude: Number,
},
{
versionKey: false,
});
module.exports = mongoose.model('Profile', profileSchema);
here is process page
import React, { useState } from "react";
import axios from "axios";
import { LogIn } from "../redux/action";
import { connect } from "react-redux";
import ImageUpload from "./PhotoUpload";
import { useNavigate } from "react-router-dom";
import { FromProcess, FromProcessContainer, ButtonCreate } from "./CreatingElements";
function CreatingAccount (props) {
const navigate = useNavigate();
const [state,setState] = useState({
currentStep: 1,
name: "",
DoB: "",
activity: "",
topics: "",
drinks: "",
about: ""
});
const handleChange = e => {
const { name, value } = e.target;
setState(state => ({
...state, // <-- copy previous state
[name]: value, // <-- update property
}));
};
const handleSubmit = async e => {
e.preventDefault();
const { user } = props;
let { name, DoB, activity, topics, drinks, about } = state;
await axios.post("/users/profile", {
name,
DoB,
activity,
topics,
drinks,
about,
id: user.id
});
const profileId = {
person: user.id,
name,
DoB,
activity,
about,
topics,
drinks
};
props.LogIn(user.id, user.nickname, profileId);
navigate("/listUsers");
};
const _next = () => {
let currentStep = state.currentStep;
currentStep = currentStep >= 2 ? 3 : currentStep + 1;
setState(state => ({
...state, // <-- copy previous state
currentStep: currentStep// <-- update property
}));
};
const _prev = () => {
let currentStep = state.currentStep;
currentStep = currentStep <= 1 ? 1 : currentStep - 1;
setState(state => ({
...state, // <-- copy previous state
currentStep: currentStep// <-- update property
}));
};
function previousButton() {
let currentStep = state.currentStep;
if (currentStep !== 1) {
return (
<>
<ButtonCreate
style={{ color: "#3103ff" }}
className="btn"
type="button"
onClick={_prev}
>
Previous
</ButtonCreate>
<br />
</>
);
}
return null;
}
function nextButton() {
let currentStep = state.currentStep;
if (currentStep < 3) {
return (
<ButtonCreate
className="btn"
type="button"
onClick={_next}
data-cy="next-process"
style={{
marginBottom: "25px",
color: "#FFF",
backgroundColor: "#3103ff"
}}
>
Next
</ButtonCreate>
);
}
return null;
}
return (
<>
<FromProcessContainer>
<FromProcess onSubmit={handleSubmit} >
<p>Step {state.currentStep}</p>
<br/>
<Step1
currentStep={state.currentStep}
handleChange={handleChange}
name={state.name}
DoB={state.DoB}
activity={state.activity}
/>
<Step2
currentStep={state.currentStep}
handleChange={handleChange}
topics={state.topics}
drinks={state.drinks}
/>
<Step3
currentStep={state.currentStep}
handleChange={handleChange}
about={state.about}
/>
{previousButton()}
{nextButton()}
</FromProcess>
</FromProcessContainer>
</>
);
}
function Step1(props) {
if (props.currentStep !== 1) {
return null;
}
return (
<div className="form-group">
<label>
<input
value={props.name}
onChange={props.handleChange}
type="text"
name="name"
placeholder="Your name"
required
data-cy="input-name-process"
/>
</label>
<label>
<input
value={props.DoB}
onChange={props.handleChange}
type="date"
name="DoB"
placeholder="Date of Birth"
max="2010-01-01"
min="1930-12-31"
required
data-cy="input-Dob-process"
/>
</label>
<label>
<input
value={props.activity}
onChange={props.handleChange}
type="text"
name="activity"
required
placeholder="Place of work or study (required)"
data-cy="input-activity-process"
/>
</label>
</div>
);
}
function Step2(props) {
if (props.currentStep !== 2) {
return null;
}
return (
<div className="form-group">
<label>
<input
value={props.topics}
onChange={props.handleChange}
type="text"
name="topics"
placeholder="Favorite topics: (Optional)"
/>
</label>
<label>
<input
type="text"
value={props.drinks}
onChange={props.handleChange}
name="drinks"
placeholder="Favorite drink: (Optional)"
/>
</label>
</div>
);
}
function Step3(props) {
if (props.currentStep !== 3) {
return null;
}
return (
<>
<ImageUpload/>
<div className="form-group">
<label>
<input
value={props.about}
onChange={props.handleChange}
className="form-control"
type="text"
name="about"
placeholder="Caption (Optional)"
/>
</label>
</div>
<button
type="submit"
className="btn"
data-cy="submit-process"
style={{
backgroundColor: "#3103ff",
marginBottom: "25px",
color: "#FFF"
}}
>
Save it
</button>
</>
);
}
const mapStateToProps = state => ({
user: state.user
});
const mapDispatchToProps = dispatch => ({
LogIn: (id, nickname, profileId) => dispatch(LogIn(id, nickname, profileId))
});
export default connect(mapStateToProps, mapDispatchToProps)(CreatingAccount);
backend for /process
router.post('/profile', async (req, res) => {
const {
name,
DoB,
activity,
topics,
about,
drinks,
avatar,
id,
} = req.body;
const user = await Person.findOne({ _id: id }).exec();
if (!user.profileId) {
const newProfile = await Profile.create({
person: id,
name,
DoB,
activity,
topics,
about,
drinks,
avatar,
});
await Person.updateOne(user, { $set: { profileId: newProfile._id } });
return res.send({
success: true,
});
}
await Person.updateOne({ _id: user.profileId }, {
$set: {
activity,
topics,
about,
drinks,
avatar,
},
});
});
In your axios post, add a .then and a .catch, console.log() the result of the post whether its a success or a failure, also, not sure if u have the favourite variable defined globally but that might also be a source of the error
Issue
In the case of backend errors the API is returning a valid response that is missing a profileId property.
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ success: true, profileId: response });
} else {
res.send({ success: false, err: 'Something went wrong' }); // <-- here, no profileId
}
});
This doesn't cause axios to return a Promise rejection and the frontend code assumes the response object has certain properties.
The error object returned is { success: false, err: 'Something went wrong' } but the code is attempting to access into an undefined profileId property.
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
setPlace(data.profileId.place); // <-- here, data.profileId undefined
setAge(data.profileId.age);
setFavorite(data.profileId.favorite);
setCaption(data.profileId.cation);
profileInit(data.profileId);
});
data.profileId is undefined, and alone isn't an issue, it's later when trying to access the place property of an undefined object that an error is thrown.
Solution
You can keep the backend code and do a check in the frontend for a successful POST request.
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
if (data.success) {
// POST success
setPlace(data.profileId.place);
setAge(data.profileId.age);
setFavorite(data.profileId.favorite);
setCaption(data.profileId.cation);
profileInit(data.profileId);
} else {
// POST failure, check error
// access data.err
}
});
It would be better to return a non-200 status code so axios can throw/handle a rejected Promise. You can read more about HTTP status codes here. Below I'm returning a super general Status 500 error, but you will want to be a specific as you need to be, i.e. a 404 if the specific person object isn't found.
Example:
router.post('/profileEdit', async (req, res) => {
const { id } = req.body;
const response = await Profile.findOne({ person: id });
if (response) {
res.send({ profileId: response });
} else {
res.status(500).send({ err: 'Something went wrong' });
}
});
...
axios
.post("/users/profileEdit", { id })
.then(({ data }) => {
// 200 responses
const {
profileId,
profileId: { age, cation, favorite, place },
} = data;
setPlace(place);
setAge(age);
setFavorite(favorite);
setCaption(cation);
profileInit(profileId);
})
.catch(error => {
// non-200 responses
});
I'm trying to display an error message when a user tries to sign in with an unregistered user but I'm not able to get that error message on the frontend(reactjs) that I am sending from my backend(nodejs, express, MongoDB).
I am using redux to handle the state of the react app.
user login form onSubmit code:
const onSubmit = (data) => {
if (isLogin) {
dispatch(signin(data, history));
} else {
dispatch(signup(data, history));
}
};
actions creators for auth
import * as api from "../api";
export const signin = (formData, history) => async (dispatch) => {
try {
// login the user
const { data } = await api.signIn(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
dispatch({ type: "ERROR", data: error.response.data.message });
}
};
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
}
};
reducers for auth:
const authReducer = (state = { authData: null }, action) => {
switch (action.type) {
case "AUTH":
localStorage.setItem("profile", JSON.stringify({ ...action?.data }));
return { state, authData: action?.data };
case "LOGOUT":
localStorage.clear();
return { state, authData: null };
case "ERROR":
return { state, authData: action?.data };
default:
return state;
}
};
export default authReducer;
Backend sign in code
const signin = async (req, res) => {
const { email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser)
return res.status(404).json({ message: "User doesn't exist." });
const isPasswordCorrect = await bcrypt.compare(
password,
existingUser.password
);
if (!isPasswordCorrect)
res.status(404).json({ message: "Invalid Credentials" });
const token = jwt.sign(
{ email: existingUser.email, id: existingUser._id },
"test",
{ expiresIn: "1h" }
);
res.status(200).json({ result: existingUser, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
sign API
import axios from "axios";
const API = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
});
export const signIn = (formData) => API.post("/user/signin", formData);
export const signUp = (formData) => API.post("/user/signup", formData);
Anyone, please help me with this.
Screenshots of the error response in Postman:
I just debugged the issue. First install redux-devtools-extension by npm install --save redux-devtools-extension
Then apply this in store(index.js file in your case) as follows
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { reducers } from "./reducers";
import { composeWithDevTools } from "redux-devtools-extension";
const middleware = [thunk];
const store = createStore(
reducers,
composeWithDevTools(applyMiddleware(...middleware))
);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
And now you can use the error message anywhere as follows (your Auth.js file)
import React, { useState } from "react";
import { useSelector } from "react-redux";
import Input from "../utils/Input";
import Label from "../utils/Label";
import { useForm, FormProvider } from "react-hook-form";
import { GoogleLogin } from "react-google-login";
import { useDispatch } from "react-redux";
import { useHistory } from "react-router";
import { signin, signup } from "../../actions/auth";
const Auth = () => {
const [isLogin, setIsLogin] = useState(true);
const formMethods = useForm();
const auth = useSelector((state) => state.auth);
const { authData } = auth;
const { handleSubmit } = formMethods;
console.log(authData);
const dispatch = useDispatch();
const history = useHistory();
const changeScreen = () => {
setIsLogin(false);
dispatch({ type: "LOGOUT" });
};
const onSubmit = (data) => {
if (isLogin) {
dispatch(signin(data, history));
} else {
dispatch(signup(data, history));
}
};
const googleSuccess = async (res) => {
const result = res?.profileObj;
const token = res?.tokenId;
try {
dispatch({ type: "AUTH", data: { result, token } });
history.push("/");
} catch (error) {
console.log(error);
}
};
const googleFailure = (error) => {
console.log(error);
console.log("Google sign in was unsuccessful");
};
return (
<section className="col-start-1 col-end-2 md:col-start-2 md:col-end-3 row-start-2 row-end-3 md:row-start-1 md:row-end-2 mx-3 sm:mx-0 md:my-auto">
<div className=" w-full max-w-md bg-primaryOne px-6 py-8 rounded-md shadow-md mx-auto">
<FormProvider {...formMethods}>
<form className="" onSubmit={handleSubmit(onSubmit)}>
<div className="w-full flex justify-around mb-2">
<button
className={`${
isLogin
? "bg-secondaryTwo"
: "transition bg-transparent hover:bg-secondaryTwo"
} text-white text-xs font-bold px-6 py-4 rounded-full`}
type="button"
onClick={() => setIsLogin(true)}
>
LOG IN
</button>
<button
className={`${
!isLogin
? "bg-secondaryTwo"
: "transition bg-transparent hover:bg-secondaryTwo"
} text-white text-xs font-bold px-6 py-4 rounded-full`}
type="button"
onClick={() => changeScreen()}
>
SIGN UP
</button>
</div>
<div>
{!isLogin && (
<div>
<Label labelName="Name" />
<Input inputName="name" type="text" bgColor="primaryTwo" />
</div>
)}
<div>
<Label labelName="Email" />
<Input inputName="email" type="email" bgColor="primaryTwo" />
</div>
<div>
<Label labelName="Password" />
<Input
inputName="password"
type="password"
bgColor="primaryTwo"
/>
</div>
</div>
<div className="text-center">
<button
type="button"
onClick={() => setIsLogin(!isLogin)}
className="text-neutral font-extralight text-xs pt-6"
>
{authData && <h1 style={{ color: "red" }}>{authData}</h1>}
{!isLogin
? "Already have an account? Log In"
: "Don't have an account? Sign Up"}
</button>
</div>
<button className="bg-secondaryTwo hover:bg-secondaryOne transition px-4 py-3 w-full rounded-md text-white font-bold mt-4 shadow-md">
{isLogin ? "Log In" : "Sign Up"}
</button>
<div className="flex items-center py-6">
<div className="w-1/2 h-px bg-white bg-opacity-40"></div>
<p className="text-white px-1 text-xs">OR</p>
<div className="w-1/2 h-px bg-white bg-opacity-40"></div>
</div>
<div>
<GoogleLogin
clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}
onSuccess={googleSuccess}
onFailure={googleFailure}
cookiePolicy="single_host_origin"
render={(renderProps) => (
<button
className="bg-blue-600 hover:bg-blue-500 transition px-4 py-3 w-full rounded-md text-white font-bold mb-4 shadow-md"
type="button"
onClick={renderProps.onClick}
disabled={renderProps.disabled}
>
<i className="fab fa-google mr-2"></i>Continue with Google
</button>
)}
/>
</div>
</form>
</FormProvider>
</div>
</section>
);
};
export default Auth;
And one last thing. Check nested object before using its properties like error.response.data.message (your auth.js actions file)
import * as api from "../api";
export const signin = (formData, history) => async (dispatch) => {
try {
// login the user
const { data } = await api.signIn(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log("An error occured while ");
const errMsg =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: "ERROR", data: errMsg });
console.log(errMsg);
}
};
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
}
};
Hope it helps!
As far as I understood, everything is working fine, and actually, there is no error happening on the frontend side. You have to check the status code of "await api.signIn(formData);" response. If it is 200, it means that everything is ok otherwise you have to check the message in the response to get the message error. As on the frontend there is thrown error to be catched.
you can aslo use react-toastify . you can get status code and response message from error and store it in state object in reducers/auth.js and access it using useSelector() then create if else conditions according to status code and pass message to toast(#error_message#).
just see react-toastify and know how to use it.
i'm currently creating my first MERN App, and everything is going well, until something happened, and i'm going my try to explain because i need help !
What i'm doing is a facebook clone, where you can post something, you can delete your post and you can update your post, the logic is simple, i call dispatch to pass the data to the actions, the actions pass the data to the backend, and the backend return something to me and it saves in my store, because i'm using redux
The problem is that, when i have 2 post, and i want to delete a post, or maybe i want to edit it, the other post dissapears, it's like it loses its id and then loses the information, then i can't do anything but reaload the page, and it happens always
this is how it looks like, everything fine
Then, after trying to edit a post, the second one lost its information, and in the console, it says that Warning: Each child in a list should have a unique "key" prop, and i already gave each post the key={_id}, but the post lost it and i don't know how
Here's the code
Posts.js
import React, { useState } from "react";
import "./Posts.css";
import moment from "moment";
// Icons
import { BiDotsVertical, BiLike } from "react-icons/bi";
import { MdDeleteSweep } from "react-icons/md";
import { AiFillLike } from "react-icons/ai";
import { GrClose } from "react-icons/gr";
// Calling actions
import { deletePost, } from "../actions/posts.js";
// Gettin The Data From Redux
import { useSelector, useDispatch } from "react-redux";
const Posts = ({ setCurrentId }) => {
const [animation, setAnimation] = useState(false);
const [modal, setModal] = useState(false);
const [modalPost, setModalPost] = useState({});
// Getting The Posts
const posts = useSelector(state => state.posts);
const dispatch = useDispatch();
// Showing And Hiding Modal Window
const ModalWindow = post => {
setModalPost(post);
setModal(true);
};
// Liking the post
// const Like = id => {
// dispatch(giveLike(id));
// setAnimation(!animation);
// };
if (!posts.length) {
return <div>Loading</div>;
} else {
return (
<div className="Posts">
{/* // Modal window for better look to the post */}
{/* {modal && (
<div className="modalWindow">
<div className="container">
<div className="container-image">
<img src={modalPost.image} alt="" />
</div>
<div className="information">
<div className="container-information">
<div className="data-header">
<h2>
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(modalPost.createdAt).fromNow()}
</span>
</h2>
<span className="data-icon" onClick={() => setModal(false)}>
<GrClose />
</span>
</div>
<div className="message">
<h2>{modalPost.title}</h2>
<p>{modalPost.message}</p>
</div>
</div>
</div>
</div>
</div>
)} */}
{/* */}
{posts.map(post => {
const { _id, title, message, image, createdAt, likes } = post;
return (
<div className="Posts-container" key={_id}>
<div className="Fit">
<div className="Fit-stuff">
<h2 className="Fit-stuff_title">
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(createdAt).fromNow()}
</span>
</h2>
<a
className="Fit-stuff_edit"
href="#form"
onClick={() => setCurrentId(_id)}
>
<BiDotsVertical />
</a>
</div>
<div className="Fit-data">
<h2 className="Fit-data_title">{title}</h2>
<p className="Fit-data_message">{message}</p>
{image ? (
<div className="Fit-img">
<img
onClick={() => ModalWindow(post)}
src={image}
alt=""
/>
</div>
) : (
<div></div>
)}
</div>
<div className="Fit-shit">
<span>
{animation ? (
<AiFillLike className="fullLightBlue" />
) : (
<BiLike />
)}
{likes}
</span>
<span onClick={() => dispatch(deletePost(_id))}>
<MdDeleteSweep />
</span>
</div>
</div>
</div>
);
})}
</div>
);
}
};
export default Posts;
The form where i call update and create Post
import React, { useState, useEffect } from "react";
import Filebase from "react-file-base64";
// For the actions
import { useDispatch, useSelector } from "react-redux";
import { createPost, updatePost } from "../actions/posts.js";
import {
Wrapper,
FormContainer,
Data,
DataInput,
SecondDataInput,
FormContainerImg,
FormContainerButtons,
Buttons
} from "./FormStyled.js";
const Form = ({ currentId, setCurrentId }) => {
const [formData, setFormData] = useState({
title: "",
message: "",
image: ""
});
const specificPost = useSelector(state =>
currentId ? state.posts.find(p => p._id === currentId) : null
);
// Sending The Data And Editing The data
const dispatch = useDispatch();
useEffect(() => {
if (specificPost) setFormData(specificPost);
}, [specificPost]);
// Clear Inputs
const clear = () => {
setCurrentId(0);
setFormData({ title: "", message: "", image: "" });
};
const handleSubmit = async e => {
e.preventDefault();
if (currentId === 0) {
dispatch(createPost(formData));
clear();
} else {
dispatch(updatePost(currentId, formData));
clear();
}
};
return (
<Wrapper>
<FormContainer onSubmit={handleSubmit}>
<Data>
<DataInput
name="title"
maxLength="50"
placeholder="Title"
type="text"
value={formData.title}
onChange={e => setFormData({ ...formData, title: e.target.value })}
/>
<SecondDataInput
name="message"
placeholder="Message"
maxLength="300"
value={formData.message}
required
onChange={e =>
setFormData({ ...formData, message: e.target.value })
}
/>
<FormContainerImg>
<Filebase
required
type="file"
multiple={false}
onDone={({ base64 }) =>
setFormData({ ...formData, image: base64 })
}
/>
</FormContainerImg>
<FormContainerButtons>
<Buttons type="submit" create>
{specificPost ? "Edit" : "Create"}
</Buttons>
<Buttons onClick={clear} clear>
Clear
</Buttons>
</FormContainerButtons>
</Data>
</FormContainer>
</Wrapper>
);
};
export default Form;
My actions
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
import * as api from "../api/posts.js";
export const getPosts = () => async dispatch => {
try {
const { data } = await api.getPosts();
dispatch({ type: GETPOSTS, payload: data });
} catch (error) {
console.log(error);
}
};
export const createPost = newPost => async dispatch => {
try {
const { data } = await api.createPost(newPost);
dispatch({ type: CREATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const updatePost = (id, updatePost) => async dispatch => {
try {
const { data } = await api.updatePost(id, updatePost);
dispatch({ type: UPDATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const deletePost = id => async dispatch => {
try {
await api.deletePost(id);
dispatch({ type: DELETEPOST, payload: id });
} catch (error) {
console.log(error);
}
};
Redux Part
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
const postData = (posts = [], action) => {
switch (action.type) {
case GETPOSTS:
return action.payload;
case CREATEPOST:
return [...posts, action.payload];
case UPDATEPOST:
return posts.map(post =>
action.payload._id === post._id ? action.payload : posts
);
case DELETEPOST:
return posts.filter(post => post._id !== action.payload);
default:
return posts;
}
};
export default postData;
My controllers in the backend
import mongoose from "mongoose";
import infoPost from "../models/posts.js";
// Getting All The Posts
export const getPosts = async (req, res) => {
try {
const Posts = await infoPost.find();
res.status(200).json(Posts);
} catch (error) {
res.status(404).json({ message: error.message });
console.log(error);
}
};
// Creating A Post
export const createPost = async (req, res) => {
const { title, message, image } = req.body;
const newPost = new infoPost({ title, message, image });
try {
await newPost.save();
res.status(201).json(newPost);
} catch (error) {
res.status(409).json({ message: error.message });
console.log(error);
}
};
// Update A Post
export const updatePost = async (req, res) => {
const { id } = req.params;
const { title, message, image } = req.body;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No Post With Id Of ${id}`);
const updatedPost = { title, message, image, _id: id };
await infoPost.findByIdAndUpdate(id, updatedPost, { new: true });
res.json(updatedPost);
};
// Deleting A Post
export const deletePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res
.status(404)
.send(`We Couldnt Found The Post With Id Of ${id} To Delete`);
await infoPost.findByIdAndRemove(id);
res.json(`Post With Id Of ${id} Deleted Succesfully`);
};
// Liking A Post
export const likePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No post with id: ${id}`);
const post = await infoPost.findById(id);
const updatedPost = await infoPost.findByIdAndUpdate(
id,
{ likeCount: post.likeCount + 1 },
{ new: true }
);
res.json(updatedPost);
};
Even though i've been trying to solve this problem for nearly 3.5 hours, i think that the problem might be in my Posts.js part, if you can help me, you're the greatest !
I am creating an 'edit profile' page for a dashboard the technologies that I use for the same are Next.js, Node.js & MongoDB.
Note: skip to the backend part if you just wanted to know the issue.
Frontend
Firstly,let me explain the Frontend part.
I am using useRef() inorder to reference data(name,bio) in the inputfields. which are working nicely.
Everything is fine the issue is in the handlesbumit() event_handler.
I am using FormData to send my form data to the backend API
If you're thinking why I'm not using a usual body object to send data the reason is that I have to add the profile picture updation later for which I have to send files , which as far I know we can't do that with an Object and yeah just to inform you it works fine if I would have used that Object part but can't use it with profilepicture updation.
The value that I have consoled out for the references are all good, and the rest of the handler is just as it is written can't find anything odd in that.
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value); //Testing
console.log(bioRef.current.value); //Testing
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value);
console.log(bioRef.current.value);
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
Backend
Now, the backend API for the same handlesubmit() event_handler i.e. 'api/user'
Please ignore the handler, it's just a predefined middleware npm next-connect which itself checks what type of request is coming if its 'PATCH' it will run handler.patch.
The Issue is the value of name & Bio is undefined,which means its not getting values from req.body;
And to check I also consoled out req.body which give out this
The data is correct but req.body is not a Object its a String now and I get it, its because I'm using formdata so how to get the values of name & Bio from this req.body ?
import nextConnect from 'next-connect';
import middleware from '../../../middlewares/middleware';
import { extractUser } from '../../../lib/api-helpers';
const handler = nextConnect();
handler.use(middleware);
handler.get(async (req, res) => res.json({ user: extractUser(req) }));
handler.patch(async (req, res) => {
if (!req.user) {
req.status(401).end();
return;
}
const { name, Bio } = req.body;
await req.db.collection('users').updateOne(
{ _id: req.user._id },
{
$set: {
name:name,
Bio: Bio,
},
},
);
res.json({ user: { name, Bio } });
});
export default handler;
I have encountered a this issue.
I was resolve it by use 2 form, a form use to get user's info as email, password and the other for send user's picture.
Maybe has best practice for this case.
I am new to react and redux so I am not able to solve this bug easily after doing plenty of research.
I am trying to display profiles of users in a separate page in form of cards but I am getting an error:
TypeError: Cannot read property 'name' of null
ProfileItem.render
src/components/profiles/Profileitem.js:15
12 | <div className="row">
13 |
14 | <div className="col-lg-6 col-md-4 col-8">
> 15 | <h3>{profile.user.name}</h3>
16 | <p>
17 | {profile.status}{' '}
18 | {isEmpty(profile.company) ? null : (
▶ 22 stack frames were collapsed.
(anonymous function)
src/actions/userprofileAction.js:77
74 | dispatch(profileLoading());
75 | axios
76 | .get('/api/userprofile/all')
> 77 | .then(res =>
78 | dispatch({
79 | type: GET_PROFILES,
80 | payload: res.data
//this is the back-end of the userprofile
userprofile.js
const express = require('express');
const router = express.Router();
const mongoose=require('mongoose');
const passport=require('passport');
//loading validation after creating the userprofie valdiation
const validateProfileInput=require('../../validation/userprofile');
const validateExperienceInput=require('../../validation/experience');
//bring profile schema model
const Profile=require('../../models/Profile');
//bringing user schema model
const User=require('../../models/User');
//testing this api
router.get('/demo', (req, res) => res.json({ msg: 'Profile Works' }));
//get request
//now need to check for the user who is trying to login
router.get('/',passport.authenticate('jwt', { session: false }),(req, res) => {
//initializing this as empty because need to add error msg
const errors = {};
//fetch current user's profile and finding from profile model
//findone is a mongoose method which will find a specifc{single} thing
Profile.findOne({ user: req.user.id }) .populate('user', ['name']).then(profile => {
//if not found display error msg
if (!profile) {
errors.noprofile = 'no profile exists for this person';
return res.status(404).json(errors);
}
//if found then show proifle
res.json(profile);
})
.catch(err => res.status(404).json(err));
}
)
//to see all profiles at api/userprofile/all
router.get('/all',(req,res)=>{
Profile.find()
.populate('user',['name'])
.then(profiles=>{
if(!profiles){
errors.noprofile='no profiles';
return res.status(404).json(errors);
}
res.json(profiles);
})
.catch(err=>res.status(404).json({profile:'no profiles'}));
})
//getting profile by name
router.get('/profilename/:profilename',(req,res)=>{
Profile.findOne({profiename:req.params.profiename})
.populate('user',['name'])
.then(profile=>{
if(!profile){
errors.noprofile='there is no profile';
res.status(400).json(errors);
}
res.json(profile);
})
.catch(err=>res.status(404).json(err));
})
//getting profile by id
router.get('/users/:users_id',(req,res)=>{
Profile.findOne({profiename:req.params.profiename})
.populate('user',['name'])
.then(profile=>{
if(!profile){
errors.noprofile='there is no profile';
res.status(400).json(errors);
}
res.json(profile);
})
.catch(err=>res.status(404).json(err));
})
//post request
router.post(
'/',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const {errors,isValid}=validateProfileInput(req.body);
//check validation
if(!isValid){
return res.status(400).json(errors);
}
//getting fields and adding in an obj
const fields={};
fields.user=req.user.id;
//checking if its sent from handle
if(req.body.profilename)fields.profilename=req.body.profilename;
if(req.body.company)fields.company=req.body.company;
if(req.body.location)fields.location=req.body.location;
//so splitting skills into an array when seperated by ','
if(typeof req.body.skills!=='undefined')
fields.skills=req.body.skills.split(',');
//searching by id and if profile has then update
Profile.findOne({user:req.user.id}).then(profile=>{
if(profile){
Profile.findOneAndUpdate({user:req.user.id},{$set:fields},{new:true})
.then(profile=>res.json(profile));
}
else{
//checking if there
Profile.findOne({profiename:fields.profilename}).then(profile=>{
if(profile){
errors.profiename='profile already there'
res.status(400).json(errors);
}
//saving and making new if not
new Profile(fields).save().then(profile=>res.json(profile));
})
}
})
}
);
//post req to add exp
router.post(
'/experience',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateExperienceInput(req.body);
// Check Validation
if (!isValid) {
// Return any errors with 400 status
return res.status(400).json(errors);
}
//to add new experience
Profile.findOne({ user: req.user.id }).then(profile => {
const newExperience = {
title: req.body.title,
company: req.body.company,
location: req.body.location,
from: req.body.from,
to: req.body.to,
description: req.body.description
};
// Add to exp array
profile.experience.unshift(newExperience);
profile.save().then(profile => res.json(profile));
});
}
);
//after adding if user wants to delete the experience
router.delete(
'/experience/:exp_id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateExperienceInput(req.body);
// Check Validation
if (!isValid) {
// Return any errors with 400 status
return res.status(400).json(errors);
}
Profile.findOne({ user: req.user.id }).then(profile => {
const remove=profile.experience
.map(item=>item.id)
.indexof(req.params.exp_id);
//splicing out of array at index 1
profile.experience.splice(remove,1)
//saving
profile.save().then(profile=>res.json(profile));
})
.catch(err=>res.status(404).json(err));
}
);
module.exports = router;
userprofileaction.js
import axios from 'axios';
import {GET_USERPROFILE,PROFILE_LOADING,GET_ERRORS,CLEAR_CURRENT_PROFILE,GET_PROFILES} from './types';
//getting current profile
export const getProfile=()=>dispatch=>{
//dispatching loading state before req
dispatch(profileLoading());
axios.get('/api/userprofile')
.then(res=>
dispatch({
type:GET_USERPROFILE,
payload:res.data
}))
.catch(err=>
dispatch({
type:GET_USERPROFILE,
payload:{}
}))
}
// Create Profile
export const createProfile = (profileData, history) => dispatch => {
axios
.post('/api/userprofile', profileData)
.then(res => history.push('/dashboard'))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
export const addExp=(experienceData,history)=>dispatch=>{
axios.post('/api/userprofile/experience',experienceData)
.then(res=>history.push('/dashboard'))
.catch(err=>dispatch({
type:GET_ERRORS,
payload:err.response.data
}))
}
export const deleteExperience = id => dispatch => {
axios
.delete(`/api/userprofile/experience/${id}`)
.then(res =>
dispatch({
type: GET_USERPROFILE,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
//loading the profile
export const profileLoading=()=>{
return{
type:PROFILE_LOADING
}
}
//clearing profile
export const clearcurrentprofile=()=>{
return{
type:CLEAR_CURRENT_PROFILE
}
}
//getting profiles
export const getProfiles = () => dispatch => {
dispatch(profileLoading());
axios
.get('/api/userprofile/all')
.then(res =>
dispatch({
type: GET_PROFILES,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_PROFILES,
payload: null
})
);
};
profileItem.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import isEmpty from '../../validation/is-empty';
class ProfileItem extends Component {
render() {
const { profile } = this.props;
return (
<div className="card card-body bg-light mb-3">
<div className="row">
<div className="col-lg-6 col-md-4 col-8">
<h3>{profile.user.name}</h3>
<p>
{profile.status}{' '}
{isEmpty(profile.company) ? null : (
<span>at {profile.company}</span>
)}
</p>
<p>
{isEmpty(profile.location) ? null : (
<span>{profile.location}</span>
)}
</p>
<Link to={`/userprofile/${profile.profilename}`} className="btn btn-info">
View Profile
</Link>
</div>
<div className="col-md-4 d-none d-md-block">
<h4>Skill Set</h4>
<ul className="list-group">
{profile.skills.slice(0, 4).map((skill, index) => (
<li key={index} className="list-group-item">
<i className="fa fa-check pr-1" />
{skill}
</li>
))}
</ul>
</div>
</div>
</div>
);
}
}
ProfileItem.propTypes = {
profile: PropTypes.object.isRequired
};
export default ProfileItem;
Profiles.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ProfileItem from './ProfileItem';
import { getProfiles } from '../../actions/userprofileAction';
class Profiles extends Component {
componentDidMount() {
this.props.getProfiles();
}
render() {
const { profiles, loading } = this.props.profile;
let profileItems;
if (profiles === null || loading) {
profileItems = <h3>Profiles are loading..........</h3>;
} else {
if (profiles.length > 0) {
profileItems = profiles.map(profile => (
<ProfileItem key={profile._id} profile={profile} />
));
} else {
profileItems = <h4>No profiles found.....</h4>;
}
}
return (
<div className="profiles">
<div className="container">
<div className="row">
<div className="col-md-12">
<h1 className="display-4 text-center">Job Seeker's profiles</h1>
<p className="lead text-center">
Explore and get in touch with a Job seeker for free!
</p>
{profileItems}
</div>
</div>
</div>
</div>
);
}
}
Profiles.propTypes = {
getProfiles: PropTypes.func.isRequired,
profile: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile
});
export default connect(mapStateToProps, { getProfiles })(Profiles);
userprofileReducer.js
import {GET_USERPROFILE,PROFILE_LOADING,CLEAR_CURRENT_PROFILE,GET_PROFILES} from '../actions/types';
//import { stat } from 'fs';
const initialstate={
//will have profile
profile:null,
profiles:null,
loading:false
}
export default function(state=initialstate, action){
switch(action.type){
case PROFILE_LOADING:
return{
...state,
loading:true
}
case GET_USERPROFILE:
return{
...state,
profile:action.payload,
loading:false
}
case GET_PROFILES:
return{
...state,
profiles:action.payload,
loading:false
}
case CLEAR_CURRENT_PROFILE:
return{
...state,
profile:null
}
default:
return state;
}
}
You first need to check profile whether it’s undefined or null and only then access its keys. You will be mostly using either ternary or && operator for such cases.
Below code should work for you
class ProfileItem extends Component {
render() {
const { profile } = this.props;
return (
<div className="card card-body bg-light mb-3">
<div className="row">
{profile && (
<div className="col-lg-6 col-md-4 col-8">
<h3>{profile.user && profile.user.name}</h3>
<p>
{profile.status}{' '}
{isEmpty(profile.company) ? null : (
<span>at {profile.company}</span>
)}
</p>
<p>
{isEmpty(profile.location) ? null : (
<span>{profile.location}</span>
)}
</p>
<Link to={`/userprofile/${profile.profilename}`} className="btn btn-info">
View Profile
</Link>
</div>
<div className="col-md-4 d-none d-md-block">
<h4>Skill Set</h4>
<ul className="list-group">
{profile.skills.slice(0, 4).map((skill, index) => (
<li key={index} className="list-group-item">
<i className="fa fa-check pr-1" />
{skill}
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
}
ProfileItem.propTypes = {
profile: PropTypes.object.isRequired
};
export default ProfileItem;
It looks like you try to read properly before the value is set there. Try to add a checking before calling it. Something like:
if(profile.user !== 'null'){
...
}
Try to console.log(this.props) first thing on entering render.
Usually you get such errors when initial render is done and the values in props do not exist yet.
The solution will be to check this.props and this.props.xxx, and if they are null, display a 'loading' message / a spinner.
As the error highlights, the bug is at following line:
<h3>{profile.user.name}</h3>
You are trying to access name of object user but problem is the object is not as you expect. Its value is null hence it does not contain a property name. You need to debug where you are populating service response in user.
for me i have covered in try catch block and it works
let TOKEN =""
try{
TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root")).user).currentUser.accessToken ;
}
catch(err){
console.log(err);
}