前端开发中遇到的bug大汇总【长期更新】

React

从2022年开始就想学习react,23年才真正有机会接触并系统的学习React。下面是我在工作中遇到的问题,记录下来方便自己或者同样是小白的你避坑。

Ant Design 3.0

因为工作的问题,并没有直接接触到antd最新的版本。在antd3的form表单提交中遇到过很多问题,下面列出一些错误的点或者代码,并解释为什么出现这种错误,以及我是怎么做解决掉这个问题的。

Form提交问题

父组件表单提交没有触发子组件表单的校验规则

问题描述:刚开始我是写了三个组件A,B,C。A中定义Form标签,A中包含B组件,B中包含C。B和C中只写入Form.Item标签。当我点击A中的提交按钮时我发现了一个问题,提交时并没有触发B、C中Form.Item里面的校验规则。
原因及解决:我在A、B、C三个组件中都使用了@Form.create()注解。下面解释一下@Form.create()是干啥的
@Form.create()是Ant Design中的一个装饰器(Decorator),用于将一个普通组件转换为带有表单功能的组件。该装饰器函数接受一个配置对象作为参数,用于配置表单的属性和行为。常用的配置项包括:
mapPropsToFields(props):将props对象中的属性映射为表单字段的初始值。
onFieldsChange(props, fields):用于监听表单字段的变化,当表单字段发生变化时会自动调用该函数。
onValuesChange(props, changedValues, allValues):当表单值发生变化时,自动调用该函数。
handleSubmit(e):表单提交的处理函数。
handleReset(e):表单重置的处理函数。
使用示例:

import { Form } from 'antd';

@Form.create()
class MyForm extends React.Component {
  // 指定表单提交的处理函数
  handleSubmit = e => {
    e.preventDefault();
    this.props.form.validateFields((err, values) => {
      if (!err) {
        console.log('Received values of form: ', values);
      }
    });
  };

  render() {
    const { getFieldDecorator } = this.props.form;

    return (
      <Form onSubmit={this.handleSubmit}>
        <Form.Item label="Username">
          {getFieldDecorator('username', {
            rules: [{ required: true, message: 'Please input your username!' }],
          })(<Input />)}
        </Form.Item>
        <Form.Item label="Password">
          {getFieldDecorator('password', {
            rules: [{ required: true, message: 'Please input your password!' }],
          })(<Input type="password" />)}
        </Form.Item>
        <Form.Item>
          <Button type="primary" htmlType="submit">
            Log in
          </Button>
          <Button onClick={this.props.form.resetFields}>
            Reset
          </Button>
        </Form.Item>
      </Form>
    );
  }
}

export default MyForm;

简单理解一下,我在ABC三个组件中都加入这个组件之后,他们相当于三个不同的form表单,提交A并不会触发B和C中表单域的校验。
去掉B和C中的注解就解决了。

动态增删复制表单项

问题描述:a{b:[{c:[]}]}表单里的b和c都是可以动态改变的。我一开始的做法是参考百度出来的结果,用table标签包裹内容,增加、删除、复制的时候相当于对table的行进行操作,这么做确实解决了动态增删复制内容的需求,但是其中隐藏着一些问题。
首先大家都知道,table的数据来源是dataSource,例子如下:

const dataSource = [
  {
    key: '1',
    name: '胡彦斌',
    age: 32,
    address: '西湖区湖底公园1号',
  },
  {
    key: '2',
    name: '胡彦祖',
    age: 42,
    address: '西湖区湖底公园1号',
  },
];

const columns = [
  {
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: '年龄',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: '住址',
    dataIndex: 'address',
    key: 'address',
    render: (test, record, index) => {
	    return (
	        <Form.Item>
	            {this.props.form.getFieldDecorator(`person[${index}].address`, {
	                initialValue: record.address,
	            })(
	                <Input/>
	            )}
	        </Form.Item>
	    )
	}
  },
];

<Table dataSource={dataSource} columns={columns} />;

用table包裹就是在columns里面写Form.Item,写法如上。
产生的第一个问题就是样式会有点丑,table有自己的边框,想去掉的话就得手动覆盖掉antd中的table样式,还是很麻烦的。
第二个问题就是,页面初始化之后dataSource的length是固定的,当length为1的时候表单域中只有person[0].address,你点击新增行去动态增加Form.Item的时候,需要去更新表单域的值,新增一个person[1].address,但是此时页面上还没有绑定此名称的控件,这个时候就会报错,报错信息我忘记了,大致意思就是你不能在在控件绑定之前操作该值。

后来我的解决办法就是参考antd3.0中动态增减表单项的例子,在表单域中新增keys,放dataSource的值,然后在页面渲染的时候便利keys中的值,动态渲染出表单项person。
这个过程中我也有遇到过问题,当页面初始化完了之后,假设dataSource的length的值为3,也就是person[0].address,person[1].address,person[2].address有值,当我修改了第二项,也就是person[1]时,删除第二项后,我们期望看到的是第二项被完整地删掉,可是实际情况是第二项没有被删掉,反而视觉上是第三行被删掉了。
原因是我在删除操作中只更新了表单域中keys的值,没有更新表单域中person的值,虽然视觉上少了一行,但是在表单域中还是有三行数据。解决办法就是在删除操作中同时更新keys和person的值。新增和复制方法就不用手动更新person的值,只需要更新keys的值,页面渲染的时候表单域中的person会自动增加一行。

第三个问题就是在给表单域绑定的时候,出现如下报错

One field name cannot be part of another, e.g. `a` and `a.b`

原因是我在绑定的时候出现了如下代码

<Form.Item>
    {this.props.form.getFieldDecorator(`person`, {
        initialValue: person,
    })(
        <Input/>
    )}
</Form.Item>
<Form.Item>
    {this.props.form.getFieldDecorator(`person[${index}].name`, {
        initialValue: person.name,
    })(
        <Input/>
    )}
</Form.Item>

不能同时绑定到a,又绑定a.b,这也是为什么上文中我绑定keys而不是直接绑定person的原因。

我还遇到过如下报错:

Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.

原因是我在写this.props.form.getFieldDecorator的时候,后面没有写全

// 错误代码
{this.props.form.getFieldDecorator('id', {
	initialValue: value.id})}
// 正确代码
{this.props.form.getFieldDecorator('id', {
    initialValue: value.id
})(
    <Input hidden={true}/>
)}

必须把表单域的值绑定到一个表单控件上。下面是getFieldDecorator的用法示例:

import { Form, Input } from 'antd';

const MyForm = ({ form }) => {
  const { getFieldDecorator } = form;

  return (
    <Form>
      <Form.Item label="Username">
        {getFieldDecorator('username', {
          rules: [{ required: true, message: 'Please input your username!' }],
          initialValue: 'John', // 设置初始值
          valuePropName: 'defaultValue', // 指定绑定的属性
        })(<Input />)}
      </Form.Item>
    </Form>
  );
};

const WrappedMyForm = Form.create()(MyForm);

export default WrappedMyForm;

在上述代码中,form.getFieldDecorator(‘username’, {…})方法将表单项与表单数据关联起来,通过指定initialValue属性来设置初始值,并通过valuePropName属性将表单值绑定到组件的defaultValue属性上。这样,在渲染时,输入框的初始值将被设置为"John"。

根据已选择的表单项动态的改变另一表单项

通过三目运算符来选择

<Form>
	<Form.Item label="多选项">
		{getFieldDecorator('type', {
            initialValue: item.type
        })(
            <Select>
            	<Option value="1">类型1</Option>
      			<Option value="2">类型2</Option>
      		</Select>
        )}
	</Form.Item>
	<Form.Item label="可变">
		{getFieldValue('type') === 1 
		? getFieldDecorator('name', {
			initialValue: item.name,
			rules: [{required: true}],
		  })(<Input/>)
		: getFieldDecorator('name', {
			initialValue: item.name,
			rules: [{required: false}],
		  })(<Input/>)
		}
	</Form.Item>
</Form>

注意,这里用的是getFieldValue('type') === 1而不是item.type === 1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值