ant design v4笔记

前言

最近在使用ant design pro的时候,遇到很多问题,也花费了不少时间,为了防止后续遗忘,特意记录一下,也算是帮大家踩坑了。

使用哪个版本

目前最新的是ant design pro v4的版本,但是网上大部分的教程还是v3甚至还要早的,v4和v3相比还是很多地方不一样的,大部分实例已经变成react hook的形式,也就是函数组件的形式,在v3的时候大多数还是使用的class。

所以如果是新手学习起步的,建议直接使用v4,学最好学最新的东西,如果是在修改老的项目,优先选用当前的版本的代码,因为改起来还是挺麻烦的,亲身经历。

子组件修改父组件的state

目前有两种情况:

1.使用class的有状态组件进行传值(class那种)

2.使用react hook的函数组件进行传值(function的那种)

下面一一展开

首先是 class 形式函数组件,

import React from "react";
import {Input} from "antd";

export default class Parent extends React.Component{

  constructor(props) {
    super(props);
    this.state ={value:""}
  }

  handleChange = (newValue) =>{
    console.log("父组件获取新值",newValue);
    this.setState({
      value:newValue
    });
  }

  render() {
    return <MyInput value = {this.state.value} onChange = {this.handleChange}/>;
  }
}
class MyInput extends React.Component{
  handleChange =(event)=>{
    // 关键部分这里的this.props会调用父组件的方法,进而修改父类的state
    this.props.onChange(event.target.value)
  }

  render() {
    return <Input value={this.props.value} onChange={this.handleChange}/>
  }
}

这个例子是在父组件中引入一个包含Input的子组件,子组件的Input组件值发生改变的时候父组件的也受影响发生改变。

因为setState是异步的所以在使用的时候,尤其涉及到count计算之类的时候,最好使用下面的形式

   this.setState((preState)=>{
      return({count:preState.count+1})
    });
   // preState是历史的状态

同样的功能使用函数组件的形式实现

import {useState} from "react"
import {Input} from "antd";

export default function Parent() {
  // useState是React Hook中的 它的参数含义如下
  // 第一个值;value 相当于class里面的this.state={value:""}
  // 第二个值:一般约定是setValue这样的形式,它的作用相当于
  // this.setState({value:"新的值"})
  const [value,setValue] = useState()
  function handleChange(newValue){
    console.log("父组件获取新值",newValue);
    setValue(newValue)
  }
  return <MyInput value={value} onChange ={handleChange} />

}

function MyInput(props){
  function handleChange(event) {
    props.onChange(event.target.value)
  }
  return <Input value={props.value} onChange={handleChange}/>
}

坑人的Form

从v3升级到v4最坑的就是Form,因为我的项目使用的class 的形式所以,这里没有使用React Hook的形式去写,但是官网上v4使用的基本上都是函数组件的形式,在v3中使用Form的时候,需要使用Form.Create包裹下组件才能使用一些值,但是在V4中是不能使用Form.Create的,所以在这期间我调查了好久,最后算是解决了,我用的例子就是官网那个可编辑表格,参考v3和官网的迁移指南最后修改完成

/*eslint-disable */
import {Form, Input, InputNumber, Popconfirm, Table} from 'antd';
import React from "react";
import {FormInstance} from "antd/es/form";

const originData: any = [];

for (let i = 0; i < 100; i+=1) {
  originData.push({
    key: i.toString(),
    name: `Edrward ${i}`,
    age: 32,
    address: `London Park no. ${i}`,
  });
}

class EditableCell extends React.Component<any, any> {

  getInput = () => {
    if (this.props.inputType === 'number') {
      return <InputNumber/>;
    }
    return <Input/>;
  };

  render() {
    const {
      editing,
      dataIndex,
      title,
      inputType,
      record,
      index,
      children,
      ...restProps
    } = this.props
    return (
      <td {...restProps}>
        {editing ? (
          // 这个地方不用再使用getFieldDecorator(这破玩意至今拼不对)
          // 这个name写了之后 初始值就要在Form上设置了 initialValues
          <Form.Item name={dataIndex} label={dataIndex} style={{margin: 0}} rules={[{
            required: true,
            message: `Please Input ${title}!`,
          }]}>
            {this.getInput()}
          </Form.Item>
        ) : (
          children
        )}
      </td>
    );

  }


}

class EditableTable extends React.Component<any, any> {
  formRef = React.createRef<FormInstance>();
  // React Hook使用的 useForm,这里使用React.createRef代替

  isEditing = record => record.key === this.props.state.editingKey;

  edit(record: any) {
    // 这里需要通过setFieldsValue
    this.formRef?.current?.setFieldsValue({
      name: '',
      age: '',
      address: '',
      ...record,
    });
    // 调用父组件的方法开始传值
    this.props.handleEdit(record)
  };

  cancel = () => {
    this.props.handleCancel()
  };

  save(key: any) {
    // getFieldsValue获取当前所选的行的值
    const row = this.formRef?.current?.getFieldsValue();
    const newData = [...this.props.state.data];
    // 根据索引匹配当前的数据
    const index = newData.findIndex((item) => key === item.key);
    if (index > -1) {
      const item = newData[index];
      newData.splice(index, 1, {...item, ...row});
    } else {
      newData.push(row);
    }
    this.props.handleSave(newData)
  };


  render() {
    const components = {
      //修改table该属性默认行为
      body: {
        cell: EditableCell,
      },
    };
    const columns = [
      {
        title: 'name',
        dataIndex: 'name',
        width: '25%',
        editable: true,
      },
      {
        title: 'age',
        dataIndex: 'age',
        width: '15%',
        editable: true,
      },
      {
        title: 'address',
        dataIndex: 'address',
        width: '40%',
        editable: true,
      },
      {
        title: 'operation',
        dataIndex: 'operation',
        render: (text, record) => {
          const {editingKey} = this.props.state;
          const editable = this.isEditing(record);
          return editable ? (
            <span>
            <a
              onClick={() => this.save(record.key)}
              style={{
                marginRight: 8,
              }}
            >
              Save
            </a>
              <Popconfirm title="Sure to cancel?" onConfirm={() => this.cancel()}>
                <a>Cancel</a>
              </Popconfirm>
          </span>
          ) : (
            <a aria-disabled={editingKey !== ''} onClick={() => this.edit(record)}>
              Edit
            </a>
          );
        },
      },
    ];


    const mergedColumns = columns?.map(col => {
      if (!col.editable) {
        return col;
      }

      return {
        ...col,
        onCell: record => ({
          record,
          inputType: col.dataIndex === 'age' ? 'number' : 'text',
          dataIndex: col.dataIndex,
          title: col.title,
          editing: this.isEditing(record),
        }),
      };
    });
    return (
      // ref属性是必须加的,这样子组件才能使用form的属性
      <Form ref={this.formRef} component={false}>
        <Table
          components={components}
          bordered
          dataSource={this.props.state.data}
          columns={mergedColumns}
          rowClassName="editable-row"
          pagination={{
            onChange: this.cancel,
          }}
        />
      </Form>

    );

  }
}

export default class Demo extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      data: originData,
      editingKey: '',
    }
  }

  handleEdit = (record: any) => {
    this.setState({editingKey: record.key});
  }

  handleCancel = () => {
    this.setState({editingKey: ''});
  }

  handleSave = (newData) => {
    this.setState({
      data: newData,
      editingKey: ''
    })
  }

  render() {
    const parentMethods = {
      handleEdit: this.handleEdit,
      handleCancel: this.handleCancel,
      handleSave: this.handleSave,
      state:this.state,
    };
    return (
      <EditableTable {...parentMethods} />
    )
  }
}

结语

大概就是这样,关键点都加上注释,我ts写的也不好,这里主要是参考实现方式吧。

大概就这样吧,じゃあ。

posted @ 2020-12-08 17:26  公众号python学习开发  阅读(240)  评论(0编辑  收藏  举报