![](/img/trans.png)
[英]How do I pass parameters between components in a React switch statement?
[英]How do I conditionally render react functional components with switch statement?
我正在尝试呈现一个多页表单以根据带有 switch 语句的step
变量显示特定页面。 令我沮丧的是,在呈现 switch 语句的调用之后没有任何结果是我遗漏了什么吗?
import React, { useState } from "react";
import { songValidationSchema } from "../../../../utilities/validation";
import { Form } from "../../../../utilities/components/form";
import SONG_CAPTURE_PROPERTIES from "../../../../utilities/constants/SongCaptureProperties";
import { groupSongMetaProperties } from "../../../../utilities/functions";
import SongDetailsPage from "./SongDetailsPage";
import "./SongUpload.css";
const SongUpload = () => {
const [step, setStep] = useState(1);
const groupedSongMetaProperties = groupSongMetaProperties(
SONG_CAPTURE_PROPERTIES,
4 // Into arrays of max length of 4.
);
const initialValues = {
song: "",
art: "",
trackName: "",
genre: "",
album: "",
artist: "",
publisher: "",
recordLabel: "",
releaseYear: "",
copyrightMessage: "",
subtittle: "",
comment: "",
unsynchronisedLyric: "",
};
const nextStep = () => setStep(step + 1);
const previousStep = () => setStep(step - 1);
const handleSubmit = (values) => console.log("Form Data: ", values);
const renderSongDetailPage = () => {
switch (step) {
case 1:
return (
<SongDetailsPage
inputNames={groupedSongMetaProperties[0]}
nextStep={nextStep}
previousStep={previousStep}
/>
);
case 2:
return (
<SongDetailsPage
inputNames={groupedSongMetaProperties[1]}
nextStep={nextStep}
previousStep={previousStep}
/>
);
case 3:
return (
<SongDetailsPage
inputNames={groupedSongMetaProperties[2]}
nextStep={nextStep}
previousStep={previousStep}
/>
);
case 4:
return (
<SongDetailsPage
inputNames={groupedSongMetaProperties[3]}
nextStep={nextStep}
previousStep={previousStep}
/>
);
}
};
return (
<Form
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={songValidationSchema}
>
<h1>SongUpload</h1>
<h3>Upload Your Songs here!</h3>
{renderSongDetailPage() // This is the function calling the switch Render.}
</Form>
);
};
export default SongUpload;
下面的组件如下:
import React from "react";
import { FormInput } from "../../../common/forms/form";
const SongDetailsPage = ({ inputNames, nextStep, previousStep, step }) => {
const getInputType = (str, step) => {
let type = "";
switch (step) {
case 1:
switch (str) {
case "song_file":
type = "file";
break;
case "song_art":
type = "image";
break;
case "track_name":
type = "text";
break;
case "genre":
type = "text";
break;
default:
type = null;
break;
}
break;
case 2:
type = "text"; // Since all fields need text in this group
break;
case 3:
switch (str) {
case "release_year":
type = "date";
break;
case "subtittle":
type = "text";
break;
default:
type = null;
break;
}
break;
case 4:
// case "unsynchronised_lyric": -> The only case in the last one
type = null;
}
return type;
};
if (inputNames == null) return;
else
return (
<span className="input-wrapper">
{inputNames.map((key, index) => {
const type = getInputType(inputNames[index], step);
if (type !== null)
<span key={key}>
<FormInput
label={inputNames[index]}
name={
inputNames[index] === "song_file"
? "song"
: inputNames[index] === "song_art"
? "art"
: inputNames[index] === "track_name"
? "trackName"
: inputNames[index]
}
type={type}
/>
;
</span>;
else <span key={key}> Yo! </span>;
})}
</span>
);
};
export default SongDetailsPage;
最后一个组件是:
import { faEye, faEyeLowVision } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React, { useEffect, useRef, useState } from "react";
import "./Form.css";
const FormInput = ({
accept,
icon,
id,
label,
onBlur,
onChange,
name,
type,
...otherProps
}) => {
const [passwordRevealed, setPasswordRevealed] = useState(false);
const inputElement = useRef(null);
const labelElement = useRef(null);
useEffect(() => {
// input-in-focus css class moves the label out of the field and shrinks it
if (inputElement.current.value !== "") {
labelElement.current.classList.add("input-in-focus");
}
});
const handleRevealPassword = () => {
setPasswordRevealed(!passwordRevealed);
if (!passwordRevealed) type = "text";
else type = "password";
inputElement.current.type = type;
};
const handleFocus = () => {
if (
document.activeElement === inputElement.current ||
inputElement.current.value !== ""
)
labelElement.current.classList.add("input-in-focus");
else labelElement.current.classList.remove("input-in-focus");
};
const handleBlur = (e) => {
if (e.target.type === "file") return;
handleFocus();
onBlur(e);
};
return (
<div className="form-input-container">
{icon && (
<span className="label-icon-container">
<FontAwesomeIcon
className="form-input-icon"
// color={defaultStyles.colors.tomato}
icon={icon}
size="lg"
/>
</span>
)}
<label>
<p ref={labelElement}>{label}</p>
<input
accept={accept}
id={id}
name={name}
onFocus={handleFocus}
onBlur={handleBlur}
onChange={onChange}
ref={inputElement}
type={type}
{...otherProps}
/>
</label>
{type === "password" && (
<span className="upendi-password-eye">
<FontAwesomeIcon
className="password-eye"
// color={defaultStyles.colors.tomato}
icon={passwordRevealed ? faEyeLowVision : faEye}
onClick={handleRevealPassword}
size="lg"
title={
passwordRevealed
? "Click To Hide Password"
: "Click To Reveal Password"
}
/>
</span>
)}
</div>
);
};
export default FormInput;
我不是 100% 确定这个建议的有效性,所以其他人应该权衡。但为了实现你想要的,你需要从你的jsx
返回一个renderSongDetailPage
而不是 jsx 并将道具作为 object 传递给成分。 然后将renderSongDetailPage
作为jsx
元素调用。 请记住, renderSongDetailPage
需要大写的RenderSongDetailPage
R
。
const RenderSongDetailPage = () => {
switch (step) {
case 1:
return SongDetailsPage({
inputNames: groupedSongMetaProperties[0],
nextStep: nextStep,
previousStep: previousStep,
});
case 2:
return SongDetailsPage({
inputNames: groupedSongMetaProperties[1],
nextStep: nextStep,
previousStep: previousStep,
});
case 3:
return SongDetailsPage({
inputNames: groupedSongMetaProperties[2],
nextStep: nextStep,
previousStep: previousStep,
});
case 4:
return SongDetailsPage({
inputNames: groupedSongMetaProperties[3],
nextStep: nextStep,
previousStep: previousStep,
});
}
};
用法:
<RenderSongDetailPage/>
如果我可以通过观察提出建议。 RenderSongDetailPage groupedSongMetaProperties
中唯一发生变化的是RenderSongDetailPage
的数组项,因此您可以按如下方式在主返回中进行渲染:
<SongDetailsPage
inputNames={groupedSongMetaProperties[step-1]}
nextStep={nextStep}
previousStep={previousStep}
/>;
这应该会给你相同的结果。 虽然我不知道你项目的全部范围所以只是一个建议。
最终你在野外看到的只是一堆if
语句,每个语句返回一个SongDetailsPage
一个代码沙箱: https://codesandbox.io/s/jolly-gagarin-n66xp9?file=/src/App.js
问题出在 SongDetailsPage 组件中。 我没有在每个 map 迭代中返回。
import {
faCalendar,
faComment,
faCompactDisc,
faCopyright,
faFileAudio,
faFileWord,
faGuitar,
faImage,
faMusic,
faNewspaper,
faPenToSquare,
faRecordVinyl,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import React from "react";
import { FormInput } from "../../../../utilities/components/form";
const SongDetailsPage = ({ inputNames, step }) => {
const getInputType = (str, step) => {
switch (step) {
case 1:
switch (str) {
case "song_file":
return "file";
case "song_art":
return "image";
default:
return "text";
}
case 2:
return "text"; // Since all fields need text in this group
case 3:
switch (str) {
case "release_year":
return "date";
case "subtitle":
return "text";
default:
return null;
}
case 4:
// case "unsynchronised_lyric": -> The only case in the last one
return null;
}
};
if (!inputNames) return;
else
return (
<>
{inputNames.map((key, index) => {
const type = getInputType(inputNames[index], step);
return ( // <- This return statement was the issue.
...
);
})}
</>
);
};
export default SongDetailsPage;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.