从道具值设置状态以发出更新请求
Setting State From props Values To Make An UPDATE Request
我有项目对象:
{
id: "",
projectName: "" ,
projectIdentifier: "" ,
description:"" ,
startDate: Date ,
endDate: Date ,
}
我有一个组件,当用户单击“更新项目”按钮时会调用该组件。他们点击的特定 Project
通过 props
传递到 UpdateProject
组件。
当我尝试 console.log(props.project)
在 const updateProject = (props) => {
行的正下方时,我可以看到对象进来了。太棒了。 :-)
{
id: 3,
projectName: "Name" ,
projectIdentifier: "1234" ,
description:"Project description" ,
startDate: "02-11-2022" ,
endDate: "02-11-2022" ,
}
但是,我无法在此组件中设置状态。我需要能够更新 Project
对象的详细信息并将该更新请求发送到服务器。
非常感谢任何帮助。
import React, { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { useNavigate, useParams } from "react-router";
import { getProject, createProject } from "../../actions/projectActions";
const UpdateProject = (props) => {
console.log(props.project); //the Project object is coming in!!!
let navigate = useNavigate();
const { id } = useParams();
const [projectName, setProjectName] = useState(props.project.projectName);
console.log(props.project.projectName); <---- this is defined in console.log :-)
console.log(projectName); <---- this is "undefined"
const [projectIdentifier, setProjectIdentifier] = useState(
props.project.projectIdentifier
);
const [description, setDescription] = useState(props.project.description);
const [startDate, setStartDate] = useState(props.project.startDate);
const [endDate, setEndDate] = useState(props.project.endDate);
const [errors, setErrors] = useState(props.project.errors);
const [state, setState] = useState({
id,
projectName: props.project.projectName,
projectIdentifier: props.project.projectIdentifier,
description: props.project.description,
startDate: props.project.startDate,
endDate: props.project.endDate,
});
console.log("state before useEffect: ", state); // <--- here, id is the only thing console logging. Every other key is returning 'undefined'
useEffect(() => {
if (props.errors) {
setErrors(props.errors);
}
props.onGetProject(id, navigate);
console.log("STATE: ", state); <--- again, id is the only thing console logging. Every other key is returning 'undefined'
}, [props.errors]);
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
id: this.state.id,
projectName: this.state.projectName,
projectIdentifier: this.state.projectIdentifier,
description: this.state.description,
startDate: this.state.startDate,
endDate: this.state.endDate,
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
对于组件的其余部分,我在 return()
方法中的输入如下所示,例如:
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames("form-control form-control-lg ", {
"is-invalid": errors.projectName,
})}
placeholder="Project Name"
name="projectName"
defaultValue={props.project.projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
anti-pattern 将传递的 props 存储到本地组件状态,直接使用 prop 值即可。您还在提交处理程序中错误地引用了 this
。 this
OFC 只是在函数组件中未定义。
据我所知,您想要从 props 初始化 projectName
,在表单中更新此值,并在提交表单后,将此 projectName
状态与项目对象一起使用作为 props 传递以更新项目。
使用 useEffect
挂钩使本地状态与 project
对象保持同步 if/when props.project
更新。
const [projectName, setProjectName] = useState(props.project.projectName);
useEffect(() => {
setProjectName(props.project.projectName);
}, [props.project.projectName]);
将此 projectName
状态与提交处理程序中的 props.project
对象合并。
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...props.project, // <-- shallow copy props.project object
id, // <-- id from params
projectName, // <-- projectName state
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
表单应使用受控输入,使用 projectName
状态作为值。
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames(
"form-control form-control-lg ",
{ "is-invalid": errors.projectName }
)}
placeholder="Project Name"
name="projectName"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
</form>
更新
由于您正试图将 class 组件转换为函数组件,因此这里有一些基本步骤:
- 将class转换为函数和主体,将
render
方法更改为函数return。
- 将组件
state
转换为 useState
挂钩。
- 将
componentDidMount
、componentDidUpdate
和 componentWillUnmount
生命周期方法转换为一个或多个具有适当依赖项数组的 useEffect
挂钩。
- 将所有对
this.state
的引用转换为新的状态变量,并将 this.props
转换为 props
或从 props
. 解构的任何变量
Class component being converted
函数组件版本:
const UpdateProject = ({ createProject, getProject, project }) => {
const navigate = useNavigate();
const { id } = useParams();
const [state, setState] = useState({
id: "",
projectName: "",
projectIdentifier: "",
description: "",
startDate: "",
endDate: ""
});
useEffect(() => {
setState(project); // update project state when project prop updates
}, [project]);
useEffect(() => {
getProject(id, navigate); // fetch project when id updates
}, [id]);
const onChange = (e) => {
setState((state) => ({
...state,
[e.target.name]: e.target.value
}));
};
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
createProject(updateProject, navigate);
};
return (
<div className="project">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h5 className="display-4 text-center">Update Project form</h5>
<hr />
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg "
placeholder="Project Name"
name="projectName"
value={state.projectName}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg"
placeholder="Unique Project ID"
name="projectIdentifier"
value={state.projectIdentifier}
onChange={onChange}
disabled
/>
</div>
<div className="form-group">
<textarea
className="form-control form-control-lg"
placeholder="Project Description"
name="description"
onChange={onChange}
value={state.description}
/>
</div>
<h6>Start Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="startDate"
value={state.startDate}
onChange={onChange}
/>
</div>
<h6>Estimated End Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="endDate"
value={state.endDate}
onChange={onChange}
/>
</div>
<input type="submit" className="btn btn-primary btn-block mt-4" />
</form>
</div>
</div>
</div>
</div>
);
};
添加 Redux
虽然您可以仍然使用react-redux
中的connect
高阶组件,但现在更常见的是使用useDispatch
和useSelector
挂钩.
import { useDispatch, useSelector } from 'react-redux';
const UpdateProject = ({ createProject, getProject, project }) => {
...
const dispatch = useDispatch();
const project = useSelector(state => state.project.project);
...
useEffect(() => {
dispatch(getProject(id, navigate)); // fetch project when id updates
}, [id]);
...
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
dispatch(createProject(updateProject, navigate));
};
...
我有项目对象:
{
id: "",
projectName: "" ,
projectIdentifier: "" ,
description:"" ,
startDate: Date ,
endDate: Date ,
}
我有一个组件,当用户单击“更新项目”按钮时会调用该组件。他们点击的特定 Project
通过 props
传递到 UpdateProject
组件。
当我尝试 console.log(props.project)
在 const updateProject = (props) => {
行的正下方时,我可以看到对象进来了。太棒了。 :-)
{
id: 3,
projectName: "Name" ,
projectIdentifier: "1234" ,
description:"Project description" ,
startDate: "02-11-2022" ,
endDate: "02-11-2022" ,
}
但是,我无法在此组件中设置状态。我需要能够更新 Project
对象的详细信息并将该更新请求发送到服务器。
非常感谢任何帮助。
import React, { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { useNavigate, useParams } from "react-router";
import { getProject, createProject } from "../../actions/projectActions";
const UpdateProject = (props) => {
console.log(props.project); //the Project object is coming in!!!
let navigate = useNavigate();
const { id } = useParams();
const [projectName, setProjectName] = useState(props.project.projectName);
console.log(props.project.projectName); <---- this is defined in console.log :-)
console.log(projectName); <---- this is "undefined"
const [projectIdentifier, setProjectIdentifier] = useState(
props.project.projectIdentifier
);
const [description, setDescription] = useState(props.project.description);
const [startDate, setStartDate] = useState(props.project.startDate);
const [endDate, setEndDate] = useState(props.project.endDate);
const [errors, setErrors] = useState(props.project.errors);
const [state, setState] = useState({
id,
projectName: props.project.projectName,
projectIdentifier: props.project.projectIdentifier,
description: props.project.description,
startDate: props.project.startDate,
endDate: props.project.endDate,
});
console.log("state before useEffect: ", state); // <--- here, id is the only thing console logging. Every other key is returning 'undefined'
useEffect(() => {
if (props.errors) {
setErrors(props.errors);
}
props.onGetProject(id, navigate);
console.log("STATE: ", state); <--- again, id is the only thing console logging. Every other key is returning 'undefined'
}, [props.errors]);
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
id: this.state.id,
projectName: this.state.projectName,
projectIdentifier: this.state.projectIdentifier,
description: this.state.description,
startDate: this.state.startDate,
endDate: this.state.endDate,
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
对于组件的其余部分,我在 return()
方法中的输入如下所示,例如:
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames("form-control form-control-lg ", {
"is-invalid": errors.projectName,
})}
placeholder="Project Name"
name="projectName"
defaultValue={props.project.projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
anti-pattern 将传递的 props 存储到本地组件状态,直接使用 prop 值即可。您还在提交处理程序中错误地引用了 this
。 this
OFC 只是在函数组件中未定义。
据我所知,您想要从 props 初始化 projectName
,在表单中更新此值,并在提交表单后,将此 projectName
状态与项目对象一起使用作为 props 传递以更新项目。
使用 useEffect
挂钩使本地状态与 project
对象保持同步 if/when props.project
更新。
const [projectName, setProjectName] = useState(props.project.projectName);
useEffect(() => {
setProjectName(props.project.projectName);
}, [props.project.projectName]);
将此 projectName
状态与提交处理程序中的 props.project
对象合并。
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...props.project, // <-- shallow copy props.project object
id, // <-- id from params
projectName, // <-- projectName state
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
表单应使用受控输入,使用 projectName
状态作为值。
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames(
"form-control form-control-lg ",
{ "is-invalid": errors.projectName }
)}
placeholder="Project Name"
name="projectName"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
</form>
更新
由于您正试图将 class 组件转换为函数组件,因此这里有一些基本步骤:
- 将class转换为函数和主体,将
render
方法更改为函数return。 - 将组件
state
转换为useState
挂钩。 - 将
componentDidMount
、componentDidUpdate
和componentWillUnmount
生命周期方法转换为一个或多个具有适当依赖项数组的useEffect
挂钩。 - 将所有对
this.state
的引用转换为新的状态变量,并将this.props
转换为props
或从props
. 解构的任何变量
Class component being converted
函数组件版本:
const UpdateProject = ({ createProject, getProject, project }) => {
const navigate = useNavigate();
const { id } = useParams();
const [state, setState] = useState({
id: "",
projectName: "",
projectIdentifier: "",
description: "",
startDate: "",
endDate: ""
});
useEffect(() => {
setState(project); // update project state when project prop updates
}, [project]);
useEffect(() => {
getProject(id, navigate); // fetch project when id updates
}, [id]);
const onChange = (e) => {
setState((state) => ({
...state,
[e.target.name]: e.target.value
}));
};
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
createProject(updateProject, navigate);
};
return (
<div className="project">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h5 className="display-4 text-center">Update Project form</h5>
<hr />
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg "
placeholder="Project Name"
name="projectName"
value={state.projectName}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg"
placeholder="Unique Project ID"
name="projectIdentifier"
value={state.projectIdentifier}
onChange={onChange}
disabled
/>
</div>
<div className="form-group">
<textarea
className="form-control form-control-lg"
placeholder="Project Description"
name="description"
onChange={onChange}
value={state.description}
/>
</div>
<h6>Start Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="startDate"
value={state.startDate}
onChange={onChange}
/>
</div>
<h6>Estimated End Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="endDate"
value={state.endDate}
onChange={onChange}
/>
</div>
<input type="submit" className="btn btn-primary btn-block mt-4" />
</form>
</div>
</div>
</div>
</div>
);
};
添加 Redux
虽然您可以仍然使用react-redux
中的connect
高阶组件,但现在更常见的是使用useDispatch
和useSelector
挂钩.
import { useDispatch, useSelector } from 'react-redux';
const UpdateProject = ({ createProject, getProject, project }) => {
...
const dispatch = useDispatch();
const project = useSelector(state => state.project.project);
...
useEffect(() => {
dispatch(getProject(id, navigate)); // fetch project when id updates
}, [id]);
...
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
dispatch(createProject(updateProject, navigate));
};
...