У меня проблема с условным рендерингом с Next.js
и Formik
на моей веб-странице.
Итак, у меня есть массив с именем commands
на моей странице, это довольно просто:
const commands = [
{
value: 'launch',
display_name: 'LAUNCH ROCKET!',
},
{
value: 'delay_launch',
display_name: 'LAUNCH IN..',
},
{
....list of elements, they are not API fetched!
}
];
И это необходимо для веб-формы (компонента) на моей странице (которая основана на Formik )
Компонент выглядит так:
<Container>
<Formik
initialValues={{ command: 'launch', arguments: 'test'}}
onSubmit={async (values, { setSubmitting }) => {
await setSubmitting(false);
await Router.push(`/${values.command}`);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit} noValidate autoComplete="off">
<Grid container spacing={3} direction="row" justify="center" alignItems="center">
<Grid item xs={3}>
<TextField
name="command"
select
label="Select command"
className={classes.dropdown}
onChange={handleChange}
onBlur={handleBlur}
value={values.command}
variant="outlined"
>
{commands.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
</Grid>
{/* IF COMMAND IN SELECT DROPDPWN === LAUNCH THEN RENDER THIS*/}
{values.command === "launch" && (
<React.Fragment>
<Grid item xs={3}>
<TextField
text-field
/>
</Grid>
<Grid item xs={1}>
<Typography variant="h3" align="center" style={{textTransform: 'uppercase', margin: '0'}}>
@
</Typography>
</Grid>
<Grid item xs={3}>
<TextField
another text-field
</TextField>
</Grid>
</React.Fragment>
)}
</Grid>
</form>
)}
</Formik>
</Container>
Как это (должно) работать?
Когда вы выбираете раскрывающийся список на странице (в форме Formik), он отображает другие поля в зависимости от значения выбора .
Проблема:
Как видите, если я продолжу писать такой код, он будет таким же, как если бы я писал каждый if
оператор один за другим.
Итак, если в моем списке команд более 10 различных команд, он будет содержать 10+ if
блоков. Но мне не нужно отображать их все сразу в моей форме с commands.map =>
. Я хочу видеть только те поля в моей форме, которые необходимы, только когда правильная команда выбрана в dropdown
.
Как это (стиль псевдокода) :
IF IN MY FORM SELECTED COMMAND:
LAUNCH => THEN ADD 2 ADDITIONAL FIELDS IN THIS FORM
DELAYED LAUNCH => THEN ADD 3 ADDITIONAL FIELDS IN THIS FORM
...
Итак, как этого добиться?
Думаю, я должен добавить 3-е поле в свой массив commands
, например:
const commands = [
{
value: 'launch',
display_name: 'LAUNCH ROCKET!',
render_code: `<React.Fragment>
<Grid item xs={3}>
<TextField
text-field
/>
</Grid>
<Grid item xs={1}>
<Typography variant="h3" align="center" style={{textTransform: 'uppercase', margin: '0'}}>
@
</Typography>
</Grid>
<Grid item xs={3}>
<TextField
another text-field
</TextField>
</Grid>
</React.Fragment>`
},
....
]
Но как визуализировать это в моей форме на основе определенного выбранного значения? Думаю, должно быть что-то вроде: Map.get(number)
, но я не нашел ни одного примера, и более того, я не знаю, как именно фрагмент кода рендеринга должен храниться в массиве. Если я сохраню его в значении string
, это нормально?
Обновлено:
Я пытаюсь использовать пример render_code
, как и приведенный выше, через:
{commands.find(x => {if (x.value === values.command) return x.rendring_code})}
Но проблема в том, что если сохранить фрагмент JSX как string
, он станет примерно таким:
code: "<React.Fragment>\n <Grid item xs={3}>\n
Со всем этим \n
для пропуска строки и других символов форматирования, но я могу 'Не храню чистый JSX
, потому что в этом случае у меня есть ошибка рендеринга, потому что <TextField>
имеет такие свойства, как onChange={handleChange}
, который объявлен / определен только внутри формы Formik
, но не за пределами страницы.