前端
刷新浏览器导致用户信息消失
I can't go to the component by manually inputting the address in the navigation bar of my web. Once I input any address in the bar, the user I've logged in with before will log out automatically and lose all info in my react store that I stored when I successfully logged in.
I forget to extract the login user info from the local storage of my browser. So, after refreshing my page, the login user data stored in the store will disappear.
I should try to get user info from local storage everytime the page is loaded and place them into redux info slot repectively
//get user from local storage and place into storage
const userLoginFromStorage = localStorage.getItem("userInfo") ? JSON.parse(localStorage.getItem("userInfo")) : null;
const usersSlices = createSlice({
name: "users",
initialState: {
userAuth: userLoginFromStorage,
},
})
//userSlices.js
//Login
export const loginUserAction = createAsyncThunk(
"user/login",
async (userData, { rejectWithValue, getState, dispatch }) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
//make http call
const { data } = await axios.post(
`${baseUrl}/api/users/login`,
userData,
config,
);
//save user into local storage
localStorage.setItem("userInfo", JSON.stringify(data));
return data;
} catch (error) {
if (!error?.response) {
throw error;
}
return rejectWithValue(error?.response?.data);
}
},
);
//Get user from local storage and place into storage
const userLoginFromStorage = localStorage.getItem("userInfo")
? JSON.parse(localStorage.getItem("userInfo"))
: null;
//Logout action
export const logoutAction = createAsyncThunk(
"/user/logout",
async (payload, { rejectWithValue, getState, dispatch }) => {
try {
localStorage.removeItem("userInfo");
} catch (error) {
if (!error?.response) {
throw error;
}
return rejectWithValue(error?.response?.data);
}
},
);
//Slices
const usersSlices = createSlice({
name: "users",
initialState: {
userAuth: userLoginFromStorage,
},
extraReducers: (builder) => {
//register
//login
builder.addCase(loginUserAction.pending, (state, action) => {
state.loading = true;
state.appErr = undefined;
state.serverErr = undefined;
});
builder.addCase(loginUserAction.fulfilled, (state, action) => {
state.userAuth = action?.payload;
state.loading = false;
state.appErr = undefined;
state.serverErr = undefined;
});
builder.addCase(loginUserAction.rejected, (state, action) => {
state.appErr = action?.payload?.message;
state.serverErr = action?.error?.message;
state.loading = false;
});
},
});
export default usersSlices.reducer;
Login.js Component
//Form schema
const formSchema = Yup.object({
email: Yup.string().required("Email is required"),
password: Yup.string().required("Password is required"),
});
const Login = () => {
const dispatch = useDispatch();
//formik
const formik = useFormik({
initialValues: {
email: "",
password: "",
},
onSubmit: (values) => {
//dispath the action
dispatch(loginUserAction(values));
},
validationSchema: formSchema,
});
//redirect
const store = useSelector((state) => state?.users);
const { userAuth, loading, serverErr, appErr } = store;
if (userAuth) return <Redirect to={`/profile/${userAuth?._id}`} />;
return (
<>
<xxx>
<>
usersSlices里的initialState会持续寻找是否有userLoginFromStroage,每次页面刷新都会去寻找. 所有用到userslices的组件都可以用到这个被保存了userLoginFromStorage的变量userAuth
//get user from local storage and place into storage
const userLoginFromStorage = localStorage.getItem("userInfo") ? JSON.parse(localStorage.getItem("userInfo")) : null;
const usersSlices = createSlice({
name: "users",
initialState: {
userAuth: userLoginFromStorage,
},
})
//get user from local storage and place into storage
const userLoginFromStorage = localStorage.getItem("userInfo") ? JSON.parse(localStorage.getItem("userInfo")) : null;
const usersSlices = createSlice({
name: "users",
initialState: {
userAuth: userLoginFromStorage,
},
})
PrivateNavbar.js Component / AdminNavbar.js Component
<button onClick={() => dispatch(logoutAction())} type="button" className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-red-500 hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-indigo-500">
<LogoutIcon className="-ml-1 mr-2 h-5 w-5" aria-hidden="true"/>
<span>Logout</span>
</button>
CategoryDropDown组件
场景: 组件加载后从数据库获取组件数据 - categoryList并通过map遍历它们并把它们显示到其他组件中。
Bug:页面初次加载时由于网络延迟categoryList可能还没有获取到数据,对其进行遍历可能会导致map方法找不到索引对象(对象为空)。
解决办法: 在使用map遍历对象前先判断对象是否为空, 确保遍历对象不为空再进行遍历。
在这里使用setTimeout不是一个好选择因为不知道什么时候能获取到数据。
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import Select from "react-select";
import { fetchCategoriesAction } from "../../redux/slices/category/categorySlice";
const CategoryDropDown = (props) => {
//dispatch action
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchCategoriesAction());
}, [dispatch]);
//select categories
const category = useSelector((state) => state?.category);
const { categoryList, loading, appErr, serverErr } = category;
// console.log(categoryList);
let allCategories = null;
// in order to prevent categoryList is empty when executing map function for categoryList, we need to make sure that
// the categoryList property is loaded before use map to iterate it.
if (categoryList) {
allCategories = categoryList?.map((category) => {
return {
label: category?.title,
value: category?._id,
};
});
}
return (
<Select
onChange={handleChange}
onBlur={handleBlur}
id="category"
options={allCategories}
value={props?.value?.label}
/>
)}
后端
在项目文件夹外面文件夹使用npm i 在项目文件夹中使用yarn add添加包没有作用
原因: node_modules文件夹没有在项目根目录下
使用sendgrid发送forgetPasswordToken两次设置发送请求头
调用forgetPasswordToken方法时,终端报错: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
try {
const token = await user.createPasswordResetToken();
// console.log(token);
await user.save();
// Build your message
const resetURL = `If you were requested to reset your password, reset now within 10 minutes, otherwise ignore this message <a href="http://localhost:3000/reset-password/${token}">Click to verify your account</a>`;
const msg = {
xxx: xxx
};
const emailMsg = await sgMail.send(msg);
res.json(emailMsg);
} catch (err) {
res.json(err);
}
解决办法: Put return in front of this as return res.send("forget password");
Can't push emailMsg data to mongoDb
After I use await emailMsg.create() and fill in all info required by emailMsgSchema, I still cannot push this email message to db
问题出在ssendEmailMsgCtrl.js末尾的函数暴露没有使用正确的格式-应该用花括号把想要暴露的函数包起来做模块化暴露而不是直接module.exports = sendEmailMsgCtrl;模块暴露加函数名 -- 这样暴露的内容为空,module.exports向外暴露的是一个对象{},这个对象在这里没有用解构赋值语句{}接受对应函数暴露的内容就是空对象{}
解决办法:在模块暴露的地方对想暴露的函数加上{}即可
module.exports = { sendEmailMsgCtrl };
部署
.gitignore 文件没有被执行
向gitignore中添加不需要添加到git缓存的目标指令后,git add .等待很久的时间, 似乎.gitignore没有被执行。
解决办法: 因为之前没有规则的.gitignore文件或者说项目文件夹索引已经checkin了,要先git rm --cached .gitignore,删除再新建gitignore往里加rule。
在确保了.gitignore 文件放在了根目录下,内容没有打错后。用git rm --cached gitignore命令删除存在本地git cache中的文件,之后在本地根目录下删除.gitignore文件。在根目录下新建.gitignore文件并添加规则,之后使用git status查看发现写在gitignore中希望被屏蔽的文件消失了。