英文:
How do I conditionally render react functional components with switch statement?
问题
I am trying to render a multipage form to display a particular page based on the step
variable with a switch statement. To my dismay, nothing is coming out after the call that renders the switch statement am I missing something?
我正在尝试使用switch语句基于`step`变量来渲染多页表单,但令我沮丧的是,在渲染switch语句后没有任何内容出现,我是否漏掉了什么?
The Component below that is as follows:
下面的组件如下:
And the last component is:
最后一个组件如下:
英文:
I am trying to render a multipage form to display a particular page based on the step
variable with a switch statement. To my dismay, nothing is coming out after the call that renders the switch statement am I missing something?
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;
The Component below that is as follows:
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;
And the last component is:
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;
答案1
得分: 2
I'm not 100% sure about the validity of this suggestion so others should weigh in. But in order to achieve what you want, you will need to return a function instead of jsx
from your renderSongDetailPage
and pass the props as an object to the component. Then call renderSongDetailPage
as a jsx
element. Remember that renderSongDetailPage
needs to RenderSongDetailPage
with a capital 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,
});
}
};
Usage :
<RenderSongDetailPage/>
If I can make a suggestion through observation. The only thing changing in that RenderSongDetailPage
function is the array item for groupedSongMetaProperties
so you could possible just render in the main return as follows :
<SongDetailsPage
inputNames={groupedSongMetaProperties[step-1]}
nextStep={nextStep}
previousStep={previousStep}
/>;
which should give you the same results. Although I do not know the entire extent of your project so just a suggestion.
Ultimately what you would see in the wild is just a bunch of if
statements each returning a SongDetailsPage
A code sandbox : https://codesandbox.io/s/jolly-gagarin-n66xp9?file=/src/App.js
英文:
I'm not 100% sure about the validity of this suggestion so others should weigh in. But in order to achieve what you want, you will need to return a function instead of jsx
from your renderSongDetailPage
and pass the props as an object to the component. Then call renderSongDetailPage
as a jsx
element. Remember that renderSongDetailPage
needs to RenderSongDetailPage
with a capital 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,
});
}
};
Usage :
<RenderSongDetailPage/>
If I can make a suggestion through observation. The only thing changing in that RenderSongDetailPage
function is the array item for groupedSongMetaProperties
so you could possible just render in the main return as follows :
<SongDetailsPage
inputNames={groupedSongMetaProperties[step-1]}
nextStep={nextStep}
previousStep={previousStep}
/>;
which should give you the same results. Although I do not know the entire extent of your project so just a suggestion.
Ultimately what you would see in the wild is just a bunch of if
statements each returning a SongDetailsPage
A code sandbox : https://codesandbox.io/s/jolly-gagarin-n66xp9?file=/src/App.js
答案2
得分: 0
The issue was in the SongDetailsPage component. I was not returning inside each map iteration.
英文:
The issue was in the SongDetailsPage component. I was not returning inside each map iteration.
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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论