[英]Can't pass form input values from function to component in react
我有一個使用劍道的多步驟表單,基本上我想做的是將 function 充電中的值傳遞到其中一個步驟,以便我可以在獲取 API GET 請求中使用用戶輸入。 通常我會用道具來做,但這里的事情是我從 function 傳遞數據。 我嘗試了useContext,但我無法讓它工作,我多次瀏覽劍道表單代碼以掌握它的方法,但我仍然無法傳遞值。 我從 onStepSubmit() 處理程序中獲取值,我可以使用 useState 在此回調之外獲取它們,但即使那樣我也無法傳遞它們。
這是主要 function 的代碼,我在其中獲取值
import * as React from "react";
import "./Main.css";
import { Form, FormElement } from "@progress/kendo-react-form";
import { Button } from "@progress/kendo-react-buttons";
import { Stepper } from "@progress/kendo-react-layout";
import { SelectVehicle } from "./components/SelectVehicle";
import { PaymentMethod } from "./components/PaymentMethod";
import chargeIcon from "../../../../img/svg-6.svg";
import { ChargingStep } from "./components/ChargingStep";
import { Payment } from "./components/Payment";
import axios from "axios";
import { AuthContext } from "../../../../shared/context/auth-context";
import Notification from "../../Vehicles/Vehicles1/components/Notification";
const stepPages = [SelectVehicle, PaymentMethod, ChargingStep, Payment];
export const Charging = () => {
const [step, setStep] = React.useState(0);
const [formState, setFormState] = React.useState({});
const [steps, setSteps] = React.useState([
{ label: "Select Vehicle", isValid: undefined },
{ label: "Method", isValid: undefined },
{ label: "Charging", isValid: undefined },
{ label: "Payment", isValid: undefined },
]);
const auth = React.useContext(AuthContext);
const [vehicleId, setVehicleId] = React.useState(false);
const [notify, setNotify] = React.useState({
isOpen: false,
message: "",
type: "",
});
const lastStepIndex = steps.length - 1;
const isLastStep = lastStepIndex === step;
const isPreviousStepsValid =
steps
.slice(0, step)
.findIndex((currentStep) => currentStep.isValid === false) === -1;
const onStepSubmit = React.useCallback(
//add fetch vehicle data based on ID
(event) => {
const { isValid, values } = event;
axios
.get(process.env.REACT_APP_BACKEND_URL + `/cars/user/${auth.userId}`)
.then((response) => {
for (var i = 0; i < response.data.vehicles.length; i++) {
if (values.vehicleID == response.data.vehicles[i]._id) {
setVehicleId(true);
return;
} else {
setVehicleId(false);
return;
}
}
});
const currentSteps = steps.map((currentStep, index) => ({
...currentStep,
isValid: index === step ? isValid : currentStep.isValid,
}));
setSteps(currentSteps);
setStep(() => Math.min(step + 1, lastStepIndex));
setFormState(values);
if (isLastStep && isPreviousStepsValid && isValid && vehicleId) {
// Send to api the data
//alert(JSON.stringify(values));
setNotify({
isOpen: true,
message: "Submitted Successfully",
type: "success",
});
} else if (isLastStep && isPreviousStepsValid && isValid && !vehicleId) {
setNotify({
isOpen: true,
message: "Wrong vehicle ID input",
type: "error",
});
}
},
[
step,
steps,
setSteps,
setStep,
setFormState,
lastStepIndex,
isLastStep,
isPreviousStepsValid,
]
);
const onPrevClick = React.useCallback(
(event) => {
event.preventDefault();
setStep(() => Math.max(step - 1, 0));
},
[step, setStep]
);
return (
<div>
<div className="vehicle__title">
<div className="main__title">
<img src={chargeIcon} alt="charging" />
<div className="main__greeting">
<h1>Charging Simulator</h1>
<p>Simulate a Charge</p>
</div>
</div>
</div>
<div className="wrapper__simulator">
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
}}
>
<Stepper value={step} items={steps} />
<Form
initialValues={formState}
onSubmitClick={onStepSubmit}
render={(formRenderProps) => (
<div style={{ alignSelf: "center" }}>
<FormElement style={{ width: 480 }}>
{stepPages[step]}
<span
style={{ marginTop: "40px" }}
className={"k-form-separator"}
/>
<div
style={{
justifyContent: "space-between",
alignContent: "center",
}}
className={"k-form-buttons k-buttons-end"}
>
<span style={{ alignSelf: "center" }}>
Step {step + 1} of 4
</span>
<div>
{step !== 0 ? (
<Button
style={{ marginRight: "16px" }}
onClick={onPrevClick}
>
Previous
</Button>
) : undefined}
<Button
primary={true}
disabled={
isLastStep
? !isPreviousStepsValid && !vehicleId
: false
}
onClick={formRenderProps.onSubmit}
>
{isLastStep ? "Submit" : "Next"}
</Button>
</div>
</div>
</FormElement>
</div>
)}
/>
</div>
</div>
<Notification notify={notify} setNotify={setNotify} />
</div>
);
};
export default Charging;
這是我需要這些值的組件的代碼。 In the async componentDidMount function i want the url to be http://localhost:8765/evcharge/api/providers/${values.stationID}/${values.pointID}
and get the params.
class OneStep extends React.Component {
data = [
{ text: "100%", id: 1 },
{ text: "75%", id: 2 },
{ text: "50%", id: 3 },
];
state = {
value: { text: "100%", id: 1 },
cost: {text: "", id: null}
};
providers = [];
async componentDidMount() {
const url = "http://localhost:8765/evcharge/api/providers";
const response = await fetch(url);
const data = await response.json();
for (var i = 0; i < data.providers.length; i++) {
this.providers.push({
text: "Provider: " +
data.providers[i]
.Title + " Cost: " + data.providers[i].kWhCost,
id: i + 1 ,
});
}
}
numberFrom = getRandomInt(30, 50, 0);
cost = getRandomInt(0.5, 2, 2);
handleChange = (event) => {
this.setState({
value: event.target.value,
});
console.log(this.data);
console.log(this.providers);
};
handleSecondChange = (event) => {
this.setState({
cost: event.target.value
})
}
render() {
return (
<div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div style={{ width: "50%", marginRight: "25px" }}>
<Button
style={{
width: "50%",
marginRight: "25px",
marginTop: "35px",
textTransform: "capitalize",
color: "#0779e4",
fontWeight: "600",
fontSize: "18px",
right: "50px",
}}
disabled={true}
look="flat"
>
From: {this.numberFrom}
</Button>
</div>
<Button
style={{
width: "50%",
marginRight: "25px",
marginTop: "35px",
textTransform: "capitalize",
color: "#0779e4",
fontWeight: "600",
fontSize: "18px",
}}
disabled={true}
look="flat"
>
Cost per kWh: {this.cost}
</Button>
</div>
<br />
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div style={{ width: "25%", marginRight: "25px" }}>
<DropDownList
data={this.data}
dataItemKey="id"
value={this.state.value}
onChange={this.handleChange}
textField="text"
defaultItem={{ text: "To" }}
/>
</div>
<div style={{ width: "75%", marginRight: "25px" }}>
<DropDownList
data={this.providers}
dataItemKey="id"
value={this.state.providers}
onChange={this.handleSecondChange}
textField="text"
defaultItem={{ text: "Select Provider..." }}
/>
</div>
</div>
<br />
<div
style={{
display: "flex",
justifyContent: "space-between",
height: "250px",
}}
>
<div style={{ width: "50%", marginLeft: "15px" }}>
<Button
style={{
width: "50%",
marginRight: "25px",
marginTop: "35px",
textTransform: "capitalize",
color: "#ff5349",
fontWeight: "600",
fontSize: "18px",
right: "30px",
}}
disabled={true}
look="flat"
>
<CountUp
start={0}
end={parseInt(
(parseFloat(this.state.value.text) - this.numberFrom) *
this.cost
)}
duration={15}
useEasing={true}
decimals={2}
prefix="Expected Cost: "
suffix=" €"
useGrouping={true}
delay={3}
/>
</Button>
</div>
<div
style={{ width: "50%", marginRight: "25px", marginBottom: "450px" }}
>
<div className="g-container">
<div className="g-number">
<CountUp
start={30}
end={parseInt(this.state.value.text)}
duration={15}
useEasing={true}
decimals={2}
suffix=" %"
useGrouping={true}
delay={3}
/>
</div>
<div className="g-contrast">
<div className="g-circle"></div>
<ul className="g-bubbles">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
</div>
</div>
);
}
}
export const ChargingStep = <OneStep />;
無需導出和使用OneStep
組件的渲染 output ,只需導出並使用OneStep
組件本身,然后您可以將所需的任何道具傳遞給它。
請注意,這里有一個功能性和基於類的組件沒有問題,因為從外部來看它們是相同的。
從包含OneStep
的文件開始,將export
語句從export const ChargingStep = <OneStep />;
export const ChargingStep = OneStep;
(或者理想情況下只是將OneStep
重命名為ChargingStep
並直接導出)。 請注意,您還必須對其他 step 組件執行此操作,以便它們都工作相同(但這就是 React 組件應該導出和使用的方式)。
然后在Charging
組件中,您可以將 return 語句中的行從{stepPages[step]}
更改為:
const StepPage = stepPages[step];
return (
// ...
<StepPage relevantProp={value}/>
// ...
)
或者,如果您不想將這些相同的組件傳遞給所有其他步驟,您可以僅為ChargingStep
步驟添加特殊處理,我在此推薦。
進一步重構
您可能會考慮稍微改變跟蹤用戶執行步驟的方式,從直接索引查找改為使用字符串名稱,這樣您就可以知道要呈現哪個組件。
你可以這樣做:
const stepPages = {
"SelectVehicle": SelectVehicle,
"PaymentMethod": PaymentMethod,
"ChargingStep": ChargingStep,
"Payment": Payment,
};
const stepPageNames = ["SelectVehicle", "PaymentMethod", "ChargingStep", "Payment"];
然后得到你正在采取的步驟:
const stepPageName = stepPageNames[step];
const StepPage = stepPages[stepPageName];
然后您可以執行以下操作:
let stepPage = <StepPage />
if (stepPageName === "ChargingStep") {
stepPage = <StepPage relevantProp={value}/>
}
並將stepPage
放在您的 return 語句中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.