使用 Formik 集成 Material UI 选择输入

问题描述 投票:0回答:1

我有一个自定义的 Material UI 多选输入,其中的自定义部分允许它预先填充初始值,从数据库中检索(它将它们加载为输入中的选定项),然后是一个名为

handleChange
的函数允许用户编辑所选元素(取消选择/删除已加载的元素,和/或添加新元素)。

这一切都按照我需要的方式在屏幕上呈现。我的问题是当我点击提交按钮时输出的内容。

代码:

      import {
        FormControl,
        InputLabel,
        ListItemText,
        MenuItem,
        OutlinedInput,
        Select,
        Button,
      } from '@mui/material';
      import React from 'react';
      import { Formik } from 'formik';
      
      export default function Notifications() {
        const usersList = [
          { id: 1, FullName: 'Name1' },
          { id: 2, FullName: 'Name2' },
          { id: 3, FullName: 'Name3' },
          { id: 4, FullName: 'Name4' },
          { id: 5, FullName: 'Name5' },
        ];
      
        const [personName, setPersonName] = React.useState([
          { id: 2, FullName: 'Name2' },
          { id: 4, FullName: 'Name4' },
        ]);
      
        const submit = values => {
          console.log('values', values);
        };
      
        const handleChange = (event) => {
          const fullName = event.target.value.slice(-1).pop();
          const selectedPerson = usersList.find((u) => u.FullName === fullName);
      
          if (
            selectedPerson &&
            !personName.some((person) => person.FullName === fullName)
          ) {
            setPersonName((prevArray) => [...prevArray, selectedPerson]);
          } else {
            const updatedArray = personName.filter((p) => p.FullName !== fullName);
            console.log('updatedArray', updatedArray);
            setPersonName((prevArray) => [...updatedArray]);
          }
          console.log('event.target.value', event.target.value);
          console.log('personName', personName);
        };
      
        return (
          <Formik onSubmit={submit}>
            {({ values, setFieldValue }) => (
              <div>
                <FormControl sx={{ m: 1, width: 210 }} size="small">
                  <InputLabel id="demo-multiple-checkbox-label">Users</InputLabel>
                  <Select
                    labelId="demo-multiple-checkbox-label"
                    id="demo-multiple-checkbox"
                    multiple
                    value={personName}
                    onChange={handleChange}
                    input={<OutlinedInput label="Users" />}
                    renderValue={(selected) => {
                      return selected.map((s, index) => (
                        <div key={index}>
                          <MenuItem key={'menuItem' + index} value={s.id}>
                            <ListItemText
                              key={'listItemText' + index}
                              primary={s.FullName}
                            />
                          </MenuItem>
                        </div>
                      ));
                    }}
                  >
                    {usersList.map((name) => {
                      return (
                        <MenuItem key={name.id} value={name.FullName}>
                          <ListItemText primary={name.FullName} />
                        </MenuItem>
                      );
                    })}
                  </Select>
                  <Button variant="contained" color="primary" type="submit">
                    Submit
                  </Button>
                </FormControl>
              </div>
            )}
          </Formik>
        );
      }

在沙盒中

我需要将它与 Formik 集成,但我真的很挣扎(现在已经尝试了几天的挣扎)。当按下提交按钮时,它被设置为记录

values
的内容(我相信根据文档here,这应该是 Formik values prop 的正确名称)。

我认为它需要使用 Formik

setFieldValue
道具,也许是从现有的
onChange
道具(目前调用自定义“handleChange”函数)调用它,但我不是 100% 确定,我在如果那是需要发生的事情,那么对于如何做到这一点感到茫然。

reactjs material-ui formik
1个回答
0
投票

经过大量的试验和错误,我设法让它做我需要的事情——选择字段预先填充了初始值,然后用户可以编辑其内容,并将选定的值传递给 Formik 的

value
道具。这是通过结合使用
useFormik
钩子、
<Formik/>
组件的
setFieldValue
道具和
<Formik/>
组件的
initialValues
道具来实现的。

希望下面的内容可以帮助将来的其他人,因为 Formik 和 MUI 文档非常有限,这使得这类事情变得非常具有挑战性。顺便说一句,我注意到开发人员不再支持 Formik,所以如果有人在 2023 年 4 月之后阅读这篇文章并且刚刚开始(即尚未对 Formik 投入大量开发工作),那么最好请改用其他库。

新代码


    import {
      FormControl,
      InputLabel,
      ListItemText,
      MenuItem,
      OutlinedInput,
      Select,
      Button,
    } from '@mui/material';
    import React, { useEffect } from 'react';
    import { useFormik } from 'formik';
    
    export default function Notifications() {
      const usersList = [
        { id: 1, FullName: 'Name1' },
        { id: 2, FullName: 'Name2' },
        { id: 3, FullName: 'Name3' },
        { id: 4, FullName: 'Name4' },
        { id: 5, FullName: 'Name5' },
      ];
    
      const [personName, setPersonName] = React.useState([
        { id: 2, FullName: 'Name2' },
        { id: 4, FullName: 'Name4' },
      ]);
    
      const formik = useFormik({
        initialValues: {
          members: personName,
        },
        onSubmit: (values) => {
          console.log('values', values);
        },
      });
    
      // This is needed to update the formik values prop every time personName changes - without this is doesn't update
      useEffect(() => {
        formik.setFieldValue('members', personName);
      }, [personName]);
    
      const handleChange = (event) => {
        const fullName = event.target.value.slice(-1).pop();
        const selectedPerson = usersList.find((u) => u.FullName === fullName);
        console.log('fullName', fullName)
    
        if (
          selectedPerson &&
          !personName.some((person) => person.FullName === fullName)
        ) {
          setPersonName((prevArray) => [...prevArray, selectedPerson]);
        } else {
          const updatedArray = personName.filter((p) => p.FullName !== fullName);
          console.log('updatedArray', updatedArray);
          setPersonName(updatedArray);
        }
        console.log('event.target.value', event.target.value);
        console.log('personName', personName);
      };
    
      return (
        <div>
          <FormControl sx={{ m: 1, width: 210 }} size="small">
            <InputLabel id="multiple-checkbox-label">Members</InputLabel>
            <Select
              labelId="multiple-checkbox-label"
              id="multiple-checkbox"
              multiple
              value={personName.map((p) => p.FullName)}
              //value={personName}
              onChange={handleChange}
              input={<OutlinedInput label="Members" />}
              renderValue={(selected) => {
                return selected.map((s, index) => (
                  <div key={index}>
                    <MenuItem key={'menuItem' + index} value={s}>
                      <ListItemText
                        key={'listItemText' + index}
                        primary={s}
                      />
                    </MenuItem>
                  </div>
                ));
              }}
            >
              {usersList.map((name) => {
                return (
                  <MenuItem key={name.id} value={name.FullName}>
                    <ListItemText primary={name.FullName} />
                  </MenuItem>
                );
              })}
            </Select>
            <Button
              variant="contained"
              color="primary"
              onClick={formik.handleSubmit}
            >
              Submit
            </Button>
         
          </FormControl>
        </div>
      );
    }

© www.soinside.com 2019 - 2024. All rights reserved.