我正在创建一个应用程序,并使用useContext+useReducer来管理我的状态。有一个功能,我让用户创建一个项目,然后将这个项目追加到项目数组状态,并导航到下一个屏幕,在那里他可以添加更多关于项目的细节。我使用react-router-dom中的useNavigate钩子。
当我引导用户到下一个屏幕时,我试图通过发送项目数组状态中的最后一个项目来传递他创建的项目。
createProject.jsx
import React, { useState, useContext, useReducer } from "react";
import FormField from "../components/formField";
import { useNavigate } from "react-router-dom";
import TextAreaField from "../components/TextFied";
import Button from "../components/button";
import ProjectContext from "../context/projects/projects-context";
import projectsReducer from "../context/projects/projects-reducer";
export default function CreateProjectPage() {
const [projectData, setProjectData] = useState({
project_name: "",
project_description: "",
});
const handleChange = (e) => {
const { name, value } = e.target;
setProjectData({ ...projectData, [name]: value });
};
const { addProject, projects } = useContext(ProjectContext);
//const [state,dispatch] = useReducer()
let navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
if (!projectData["project_name"]) {
alert("Project Name cannot be empty");
return;
}
// Call the Create Project post Service now.
fetch("http://localhost:5000/project/createProject", {
credentials: "include",
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(projectData),
})
.then(async (res) => {
const response = await res.json();
if (res.status == 201) {
addProject(response); // This method dispatches the add project request and adds the new project which is in the response
// to the Projects State.
navigate("/add-project-details", {
state: { project: projects[projects.length - 1] },
});
} else {
}
})
.catch((err) => {
console.log(err);
});
setProjectData({
...projectData,
project_name: "",
project_description: "",
});
};
return (
<div>
<h2>Create Project</h2>
<div className="timeline">
<span className="active">1</span>
<span className="inactive">2</span>
</div>
{/* <h3 className="darkGrey mb-50">Basic Info</h3> */}
<form action="POST" onSubmit={handleSubmit}>
<div className="form-field-block">
<FormField
name="project_name"
type="text"
value={projectData["project_name"]}
onChange={handleChange}
label="Project Name"
/>
</div>
<div className="form-field-block">
<TextAreaField
name="project_description"
type="text"
label="Project Description"
onChange={handleChange}
value={projectData["project_description"]}
/>
</div>
<Button style="primary" type="submit" value="Create Project" />
</form>
</div>
);
}
这是addProject(response)调用projectsState中的方法。JSX,然后将请求发送到projects数组中。
projectsState.jsx
import { useEffect, useReducer } from "react";
import { SET_PROJECTS, ADD_PROJECT, ADD_PRIORITY } from "./projects-actions";
import projectsReducer from "./projects-reducer";
import ProjectsContext from "./projects-context";
const ProjectsState = (props) => {
const initialState = {
projects: [],
};
const [state, dispatch] = useReducer(projectsReducer, initialState);
const setProjects = (projects) => {
dispatch({
type: SET_PROJECTS,
payload: projects,
});
};
const addProject = (project) => {
dispatch({
type: ADD_PROJECT,
payload: project,
});
};
const addPriority = (priorityObj) => {
dispatch({
type: ADD_PRIORITY,
payload: priorityObj,
});
};
return (
<ProjectsContext.Provider
value={{ projects: state.projects, addProject, setProjects, addPriority }}
>
{props.children}
</ProjectsContext.Provider>
);
};
export default ProjectsState;
projectReducer.jsx
import { SET_PROJECTS, ADD_PROJECT, ADD_PRIORITY } from "./projects-actions";
import { getProjectObj, addPriorityToProject } from "./project-util";
import Project from "./project-class";
const projectsReducer = (state, action) => {
switch (action.type) {
case SET_PROJECTS:
const projectObjs = [];
// Create project objects and add it in the projects array
for (const project of action.payload) {
const projectObj = getProjectObj(project);
projectObjs.push(projectObj);
}
return {
projects: [...projectObjs],
};
case ADD_PROJECT:
// create Project Object
const projectObj = getProjectObj(action.payload);
console.log(projectObj);
return {
projects: [...state.projects, projectObj],
};
case ADD_PRIORITY:
// These lines of code are being called after the navigate statement in the createProject file (line 41).
// Because of which the user is being redirected to the next screen without the new project added.
let projects = addPriorityToProject(action.payload, state.projects);
console.log(projects);
return {
...state,
project: [...projects],
};
default:
return state;
}
};
export default projectsReducer;
但是当我在创建项目后运行代码时,当用户被重定向到additionalDetails页面时,正在传递的项目不是最新的。
当我使用调试器时,我发现addProject被调用,然后它调用调度程序,但之后控件返回到createProject文件和useNavigate行被执行,然后控件返回并更新项目数组中的项目。但到那时,用户已经导航到下一个屏幕,其中包含错误的项目。
你能告诉我我做错了什么吗?
谢谢!
一种方法是使用projects.length
:
const { addProject, projects } = useContext(ProjectContext);
const navigate = useNavigate();
useEffect(() => {
navigate("/add-project-details", {
state: { project: projects[projects.length - 1] },
});
},[navigate, projects])
只有当实际项目被推送时,我们才应该触发导航函数,然后您将获得数组中的最后一个数据和正确的页面。
第二种方法可能行不通,但值得一试:
const handleSubmit = (e) => {
e.preventDefault();
if (!projectData["project_name"]) {
alert("Project Name cannot be empty");
return;
}
// Call the Create Project post Service now.
fetch("http://localhost:5000/project/createProject", {
credentials: "include",
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(projectData),
})
.then(async (res) => {
const response = await res.json();
if (res.status == 201) {
addProject(response);
} else {
}
})
.then(() => { // seperate addProject and navigate function
navigate("/add-project-details", {
state: { project: projects[projects.length - 1] },
});
})
.catch((err) => {
console.log(err);
});
setProjectData({
// ...projectData, // <- no need for this to reset to default state
project_name: "",
project_description: "",
});
};