React - Input框绑定动态State和监听onChange事件,输入时失去焦点

发布于:2024-05-11 ⋅ 阅读:(170) ⋅ 点赞:(0)

React - Input框绑定动态State和监听onChange事件,输入时失去焦点

一. 案例复现

案例代码如下:

import React, { useState } from 'react';
import { Table, Input } from 'antd';
const Column = Table.Column;
const mockData = [{
  id: 1,
  name: 'test1',
  address: 'address1',
}, {
  id: 2,
  name: 'test1',
  address: 'address2',
}];
const index = () => {
  const [ data, setData ] = useState(mockData);

  const handleChange = (event: any, record: any, name: string) => {
    const currentVal = event.target.value;
    const { id } = record;
    const newData = data.map((item: any) => {
      return {
        ...item,
        [name]: item.id === id ? currentVal : item[name],
      };
    });
    setData(newData);
  };

  const AddressColumn = (props: any) => {
    const { record } = props;
    return <Input value={record.address} onChange={event => handleChange(event, record, 'address')} />;
  };

  return (
    <>
      <Table
        rowKey='id'
        style={{ width: '100%' }}
        dataSource={data}>
        <Column title='ID' key='id' dataIndex='id' />
        <Column title={'name'} key='name' dataIndex='name' render={(val: string, record: any) => {
          return <Input value={val} onChange={event => handleChange(event, record, 'name')} />;
        }} />
        <Column title={'address'} key='address' dataIndex='address' render={(val: string, record: any) => <AddressColumn record={record} />} />
      </Table>

    </>
  );
};

export default index;

页面如下
在这里插入图片描述
简单画了一个表格:

  1. name列可以修改,并且会动态修改对应的state
  2. address列同理,只不过用的是子组件AddressColumn渲染。

分别尝试在name列以及address列中更改Input框的内容,效果如下:
在这里插入图片描述

仔细观察可以发现:

  1. name列中的文本,可以随意输入,没有任何的限制。
  2. address列中的Input框内容一旦更改,就会失去焦点。

原因如下:

  1. 每次修改address列中的属性,动态修改了state的值。
  2. 组件重新渲染,导致AddressColumn组件也重新渲染。因此会生成一个新的Input框,导致失焦。

二. 解决方案

方式一:就如上述案例一样,采用name列式的写法,即将子组件的内容,提升到父组件中

<Column title={'address'} key='address' dataIndex='address' render={(val: string, record: any) => <AddressColumn record={record} />} />

改为
<Column title={'address'} key='address' dataIndex='address' render={(val: string, record: any) => {
  return <Input value={val} onChange={event => handleChange(event, record, 'address')} />;
}} />

方式二:使用useMemo钩子,封装一下子组件AddressColumn 避免重复渲染。

const AddressColumn = (props: any) => {
  const { record } = props;
  return <Input value={record.address} onChange={event => handleChange(event, record, 'address')} />;
};

改为
const AddressColumn = useMemo(() => (props: any) => {
  const { record } = props;
  return <Input value={record.address} onChange={event => handleChange(event, record, 'address')} />;
}, []);

网站公告

今日签到

点亮在社区的每一天
去签到