我在网页上使用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!
}
];
我的页面上需要一个web表单(组件((基于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
...
那么如何做到这一点呢?
我想我应该在我的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
表单内部声明/定义,而不在页面外部声明/定义。
我在Formik的Github Issue#751和本文中发现了一个相关的问题。因此,我找到了一个不同的,但相关的解决方案,我的问题。
以下是@CodeSandbox和StackOverflow的一个片段。
因此,该解决方案是基于原始表单的子组件,该子组件是基于选择字段呈现的。(这正是我所需要的(。
不幸的是,我并没有解决重复代码的问题,而是很好地构建了代码,只呈现了表单的必要部分