Material UI和Formik配合使用时要注意的一些问题

这段时间应新公司要求,开始搞前端啦,而且要用以前从没接触过的React框架来做,是有点压力的,而且也踩了不少坑。现在把其中一些经验教训总结下。

关于Material UI

就和饿了么的Element UI是基于Vue的UI框架一样,Material UI是基于React的UI框架,提供了很多封装好的组件,便于前端开发者进行页面开发。
官方网站:https://material-ui.com/zh/getting-started/installation/

Material UI 用法实例

下面用一个例子,假设要做一个搜索用户的功能,使用Material UI 里提供的输入框和按钮来做。那么关键代码如下:

先导入输入框和按钮控件:

import { TextField, Button } from '@material-ui/core';

然后定义一个变量,表示用户输入的搜索内容:

const [searchContent, setSearchContent] = React.useState("");

这里变量的定义用到了React的Hooks功能,上面代码的意思是定义了一个名为searchContent的变量,初始值为“”,而setSearchContent()是对这个变量进行更新的方法,要更新的话传入新值即可。

关于React的Hooks用法,可查看文档:https://reactjs.org/docs/hooks-intro.html

当然React也要导入才行:

import * as React from 'react';

然后UI的部分可以这么写,其中的中文注释部分需要去掉才能使用:

        <TextField
          value={searchContent}
          onChange={onUserNameChange}  对输入文字的监听事件
          variant="outlined" 	样式为外边框
          size="small"		大小
          className={classes.searchInput} css样式/>
        <Button
          variant="contained"	样式为颜色填充
          color="secondary"		填充的颜色
          className={classes.searchButton} css样式
          disabled={searchContent == ""} 输入框没有输入时按钮不可点击
          onClick={handleSearch}> 点击事件
          search		按钮上的文字
        </Button>

样式定义(className部分)我就不贴了,反正效果是这样:
在这里插入图片描述
关于上面的一些属性,需要说一下的是,TextField的onChange属性是用来监听、记录用户输入的关键。

对输入文字的监听事件,定义如下:

  const onUserNameChange = (event) => {
  	// event.target.value即为输入框输入的文字
    setSearchContent(event.target.value)
  }

还有搜索按钮的点击事件:

  const handleSearch = async (event) => {
    const response = await searchUser(searchContent);
    //searchUser即为搜索接口,就不贴代码了,下面可以对response进行处理
    ···
  }

这样我们就完成了使用 Material UI 开发一个输入和搜索的初步功能。

关于Formik

Formik是Form表单库,使用它可以方便地管理表单的数据更新提交等功能,可以在React 或者 React Native里使用。
官方网站:https://formik.org/docs/overview

Formik的方便之处,在于变量和UI控件的双向绑定,变量的更新会直接刷新UI,同时用户的输入等操作也会直接更新变量的值。看个例子:

Formik的使用实例

在这里插入图片描述
这是个很丑很简单的表单,功能是修改用户名,其中输入框是用来输入的,右边的按钮是自动生成用户名,下面的按钮是提交按钮。

那么用Formik如何实现呢,先创建用户信息实体,以传入这个表单:

  interface UserInfoEntity {
    userId: string;	//用户ID
    userName: string;	//用户名
  };
	
  // 创建一个用户对象信息,初始化用户名为空
  const createEmptyUserInfo = () : UserInfoEntity => {
    return {
      userId: myId,//这里的myId即为要设置用户名的用户ID
      userName: "",
    }
  }

然后UI的编写,先导入相关控件:

import { Box, Button, Typography } from '@material-ui/core';
import { Formik, Form, Field } from "formik";
import { TextField } from 'formik-material-ui';

然后UI实现:


<Formik
  onSubmit={(values) => {handleSubmit(values);}}
  initialValues={createEmptyUserInfo()}>
  {({ setFieldValue }) => (
    <>
      <Form>
        <Box className={classes.dialogItem}>
          <Typography className={classes.dialogItemTitle}>
            Name
          </Typography>
          <Field
            component={TextField}
            variant="outlined"
            size="small"
            className={classes.dialogItemInput}
            type="text"
            name="userName"
          />
          <Button
            variant="outlined"
            color="secondary"
            className={classes.generateButton}
            onClick={()=>{setFieldValue('userName', getRandomString())}}
          >
            Generate
          </Button>
        </Box>

        <Button 
          type="submit" 
          color="secondary" 
          variant="contained"
        >
          Done
        </Button>
      </Form>
    </>
  )}
</Formik>

看着有点复杂,解释一下:

  1. 第二行onSubmit={(values) => {handleSubmit(values);}}意思就是表单提交时所执行的方法为handleSubmit(values)。那么怎么触发表单提交呢?看最后一个按钮,其type=“submit”,就指定了点击这个按钮,会触发表单提交,不用再设置onClick。
  2. 然后values就是第三行initialValues所指定的值,本例中也就是createEmptyUserInfo()的返回值。initialValues是初始值,用户经过各种操作,最后提交的时候,传入handleSubmit(values)的values就是更新后的值。
  3. <Field component={TextField} type=“text” name=“userName”/> 这段就指定了一个类型为文本的输入框,其绑定的字段名为“userName”。也就是我们传入表单的用户信息实体的userName属性。我们在文本框输入,或者点击“generate”按钮自动生成用户名时,这个实体的userName的值都会随之改变,不用像纯使用Material UI那样添加onChange事件手动更新。
  4. 点击“generate”按钮,自动生成用户名,这个是怎么实现的呢,它设置了onClick属性:onClick={()=>{setFieldValue(‘userName’, getRandomString())}}意思就是点击按钮,设置“userName”这个属性的值为getRandomString()方法返回的值。setFieldValue()方法是Formik提供的方法,用来更新组件的值。

再贴一下上面需要的几个方法:

  // 生成5位随机字符串
  const getRandomString = () => {
    let t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz12345678",
      a = t.length,
      n = "";
    for (let i = 0; i < 5; i++) {
      n += t.charAt(Math.floor(Math.random() * a));
    }
    return n;
  }

  const handleSubmit = async (entity: UserInfoEntity) => {
  	// setUserName方法是自定义的API请求方法,用来设置用户名,就不贴代码了
    const response = await setUserName(entity);
    // 下面对response 做处理
    ···
  };

这样,就初步实现了Formik做表单输入框和按钮提交的配合使用。

Material UI 和Formik一起使用的坑

上面展示了Material UI 和Formik分别如何使用。那如果一块使用,就要特别小心了。

细心的你可能注意到,Material UI单独使用的时候,用到的TextField控件是自己的,而Formik单独使用的时候,也会导入自己的TextField。如果你稍不注意,就用混了。

那么Formik如果用了Material的TextField,会怎么样呢,我踩过的一个坑就是,Formik的validation,即表单验证规则会失效,本例中没有用到。
而Material UI 如果使用了Formik的TextField,则设置onChange属性会失效。总之弄混了都不能正常工作。

除了TextField之外,还有CheckBox等控件,在它们那命名都一样的。

那有什么好办法可以解决吗?起码有两个办法:
1.封装控件。比如封装Material UI的TextField,命名为MaterialTextField。然后在其他地方使用封装的控件,不要使用原始控件。

2.用import as进行重命名。比如import { TextField as MaterialTextField } from '@material-ui/core';就把Material UI的TextField重命名为MaterialTextField。然后在本文件中就可以用MaterialTextField进行使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值