NextJS 和 Formik:select 下拉列表中的条件/动态呈现表单字段
NextJS and Formik: Conditional / Dynamic rendering form fields on select dropdown
我在网页上使用 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>
它(应该)如何工作?
当您在页面上 select 下拉菜单(以 Formik 的形式)时,它会呈现其他字段,具体取决于 select 值 .
问题:
正如你所看到的,如果我继续这样写代码,它会是一样的,就好像我把每个 if
语句一个一个地写出来。
所以如果我的命令列表有 10 多个不同的命令,它将有 10+ if
个块。但是我不需要使用 commands.map =>
在我的表单中一次渲染它们。我只想查看我的表单中需要的那些字段,只有在 selected in 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
...
那么如何实现呢?
我想我应该在我的 commands
数组中添加第 3 个字段,例如:
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>`
},
....
]
但是如何根据确定的 selected 值在我的表单中呈现它?我猜应该是这样的: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}
之类的属性 declared/defined 仅在 Formik
表单内,但不在页面外。
我在 Formik 的 Github Issue #751 and at this article 上发现了一个相关问题。所以我发现了一些不同但相关的问题解决方案。
这里是snippet @CodeSandbox and 。
所以解决方案是基于原始表单的子组件,它是基于 select 字段呈现的。 (正是我需要的)。
不幸的是,我没有解决重复代码问题,而是很好地构建代码并只呈现表单的必要部分。
我在网页上使用 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>
它(应该)如何工作?
当您在页面上 select 下拉菜单(以 Formik 的形式)时,它会呈现其他字段,具体取决于 select 值 .
问题:
正如你所看到的,如果我继续这样写代码,它会是一样的,就好像我把每个 if
语句一个一个地写出来。
所以如果我的命令列表有 10 多个不同的命令,它将有 10+ if
个块。但是我不需要使用 commands.map =>
在我的表单中一次渲染它们。我只想查看我的表单中需要的那些字段,只有在 selected in 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
...
那么如何实现呢?
我想我应该在我的 commands
数组中添加第 3 个字段,例如:
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>`
},
....
]
但是如何根据确定的 selected 值在我的表单中呈现它?我猜应该是这样的: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}
之类的属性 declared/defined 仅在 Formik
表单内,但不在页面外。
我在 Formik 的 Github Issue #751 and at this article 上发现了一个相关问题。所以我发现了一些不同但相关的问题解决方案。
这里是snippet @CodeSandbox and
所以解决方案是基于原始表单的子组件,它是基于 select 字段呈现的。 (正是我需要的)。
不幸的是,我没有解决重复代码问题,而是很好地构建代码并只呈现表单的必要部分。