# 📆 2021.01.02

# 问题一

  1. 问题描述:使用EditableProTable组件,一直点击不了

  2. 解决:

// 官网,使用了key,作为唯一值,
<EditableProTable rowKey="id" ... />
// 自己项目,使用了key,作为唯一值,所以rowKey要改成使用可以
<EditableProTable rowKey="key" ... />
1
2
3
4

# 问题二

  1. 问题描述:使用 mock 请求数据,但是请求不了,根据就执行不了postMoldingData函数
...
export default {
  'POST /api/v1/molding?sn=dev1&example=query_workshopd': postMoldingData,
};

1
2
3
4
5
  1. 解决:将请求的接口改成如下,这是不是说明,设置自定义接口不能携带&?呢?
...
export default {
  'POST /api/v1/molding': postMoldingData,
};

1
2
3
4
5

# 📆 2021.01.03

  1. 问题描述:在antd pro v5 项目中,使用openAPI 的方式只要接入swagger。现有post接口,需要发送requestBody,但一直显示requestBody发送了空数据

  2. 解决:给requestBody中的内容设置格式限制

// 之前,得到requestBody为空
 "requestBody": {
          "description": "List of user object",
          "content": {
            "*/*": {...
// 现在,能准确得到requestBody的值
 "requestBody": {
          "description": "Please input request body value ",
          "content": {
            "application/json": {...
1
2
3
4
5
6
7
8
9
10

# 📆 2021.01.06

# 问题一

  1. 问题描述:使用form表单验证validator callback警告
  2. 解决:
return new Promise((resolve, reject) => {
  reject("不能重复");
});
//或
return Promise.reject("不能重复");
1
2
3
4
5

# 问题二

  1. 问题描述:使用EditableProTable组件,用来实现可编辑行,现需要对于可编辑行的表单项进行验证,一般来说使用使用form表单的rulesvalidator进行验证,很明显只抛出了错误,没有给出提示。
  2. 解决:手动添加提示,主要代码实现如下
 const [checkIdMsg, setCheckIdMsg] = useState('');
   const checkId = (_, value, callback) => {
    if (value) {
      let isRptId = dataSource.some((item) => item.id === value);
      if (isRptId) {
        setCheckIdMsg('id不能重复');
        return Promise.reject();
      } else {
        setCheckIdMsg('校验成功');
        return Promise.resolve();
      }
    } else {
      setCheckIdMsg('此项为必填项');
      return Promise.reject('此项为必填项');
    }
  };
...其它代码
 {
      title: 'id',
      key: 'id',
      // key: `${dataSource.map((item)=>item.sn)}`,
      dataIndex: 'id',
      width: '30%',
      formItemProps: (form, { rowIndex }) => {
        return {
          rules: [
            {
              validator: checkId,
              message: checkIdMsg ? checkIdMsg : '此项为必填项',//validator后能跟message,还能这样子写?!
            },
          ],
        };
      },
      editable: (text, record, index) => {
        if (text) {
          return false;
        }
      },
    },
...其它代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 📆 20220112

# 问题一

  1. 问题描述:React 中使用dva进行开发,出现以下报错信息。
 Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(ConfigInjMachine) in connect options.
1
  1. 解决:文件名写错,model.js写成modles.js,注意不要将文件名写错!

# 📆 20220115

  1. 问题描述:React+antd pro 的开发中,有孙子组件<GrandsonCmpt>,儿子组件<SunCmpt>,父亲组件<FatherCmpt>。在孙子组件中使用 dispatch 传最新数据dataSource,在父亲组件中拿到这个数据并渲染出来,但在父亲组件中渲染不出来。
  2. 原因:在父亲组件中使用setTimeout打印数据,是能够打印出来,说明是和事件的循环机制有关。
  3. 具体实现

实现一:

//父亲组件
const { dataSource, columnsSource } = this.props;
setTimeout(() => {
  //能打印这个数据
  console.log("setTimeout", dataSource);
});
// 孙子组件的实现
handleOk = async () => {
      const {handleModal}=this.props
    this.props.dispatch({ type: `${namespace}/setModalVisible`, payload: false });
    try {
    const { FormItemValue } = this.props;
    switch (Object.keys(FormItemValue)[0]) {
      case 'add':
    try {
    const formValues =await  this.form.current.validateFields()
    this.props.dispatch({ type: `${namespace}/setModalVisible`, payload: false });
    }
    // 调用父组件中的方法
    this.props.getModalData()
    catch (error) {}
        break;

      default:
        break;
    }
  };
// 父亲组件
getModalData=()=>{
  // 这个方法是给孙子组件调用,用于获取model的表单里最新数据,因为settimeout才能获取最新数据, 说明是异步调用问题
  // 获得model的表单的数据属于异步任务,而dataSource渲染是主任务,要让dataSource再更新,放在异步之后再调用更新
  // 使用[...]更新地址地址,表格才会从新渲染
  this.setState({
    dataSource1:[...this.props.dataSource]
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

问题:数据得到了更新,实现的整个过程就是孙子组件调用父组件中的方法,具体操作就是 将这个方法传给儿子组件,儿子组件再传给孙子组件,孙子组件调用这个方法,很繁琐的过程 ,并且耦合度过高,不易于后期的维护。

实现二:

// 父亲组件
<Table
  rowSelection={rowSelection}
  columns={columnsSource}
  //   {dataSource}改成{[...dataSource]}
  dataSource={[...dataSource]}
/>
1
2
3
4
5
6
7

原因:数组类型的数据(数组是引用类型的数据),单纯的赋值,只是改变了数据的指向,其数据的地址没有变化。在此项目中直接将返回结果直接赋值那么 react 会认为你这个数组没有更新(react 数据的更新是根据数据地址的变化进行更新的),可以尝试下将数据用 es6 的扩展运算符展开,比如 list = [...获取到的数据],然后再 setState,当然也有可能是 rowKey 没有更新的原因,如果你的数据量不是很大,可以尝试给 rowKey 加上一个时间戳。

参考:antd+react 数据更新后,Table 组件不刷新 (opens new window)

// 父亲组件
<Table
  rowKey={(record) => {
    return record.id + Date.now(); //在这里加上一个时间戳就可以了
  }}
  rowSelection={rowSelection}
  columns={columnsSource}
  dataSource={{dataSource}
/>
1
2
3
4
5
6
7
8
9

# 问题二

  1. 问题描述:使用 antd 开发,使用<Modal><Form>弹出表单框,将数据进行修改。点击确定修改按钮之后,显示的是上一次修改的数据。
  2. 原因:修改的数据没有及时更新,说明数据是修改了,但是没有得到及时的更新渲染
  3. 解决:让每次的<Form>表单的key不一样
<Form key={(Math.random() * 1000000).toFixed(0)} ...do something/>
1

# 问题三

  1. 问题描述:生成 antd 列表组件的时候需要要有唯一的 key
  2. 解决:
// 比如,以下操作实现了产生随机不重复的key
<Form key={new Date() + (Math.random() * 1000000).toFixed(0)} />
1
2

# 📆 20210117

  1. 问题描述:使用 React,antdpro,dva 进行开发。现有儿子组件,封装了上传文件功能,将上传文件后的内容数据fileContent使用dva进行管理;在父组件中拿到fileContent,然后更新dataSource,但在更新后,在父组件添加数据后,一直得不到新数据,只有拿到fileContent的数据。
  2. 解决:
目录结构:
├── JsonTable1
    ├── components
        ├──UploadFile
           ├──index.jsx
    ├──index.jsx
    ├──modle.js
    ├──utils.js
1
2
3
4
5
6
7
8
//部分代码
function FatherCmpt(props) {
  const { fileContentRes } = props;
  const [dataSource, setDataSource] = useState(fileContentRes);
  console.log("外面的dataSource", dataSource);
  const [DataSourceTemp, setDataSourceTemp] = useState(false);
  // 改后这样写1
  useEffect(() => {
    setDataSource(fileContentRes);
    fileContentRes.length !== 0 && setDataSourceTemp(!DataSourceTemp);
  }, [fileContentRes]);
  // 改后这样写2
  useEffect(() => {
    generateColumns();
  }, [DataSourceTemp]);

  const generateColumns = () => {
    let arrKeys = ["sn", "name", "ip"];
    let tmp = arrKeys.filter((item) => item !== "key");
    let columnsValue = tmp.map((item) => {
      return {
        title: item,
        key: item,
        dataIndex: item,
        width: "30%",
        valueType: showIptNum(item),
      };
    });
    columnsValue.push({
      title: "Action",
      valueType: "option",
      width: 200,
      render: (text, record, _, action) => {
        console.log("里面的dataSource", dataSource);
        return (
          <Space>
            <a
              key="editable"
              onClick={() => {
                setDelData(record);
                action?.startEditable?.(record.key);
              }}
            >
              编辑
            </a>
            <Popconfirm
              title="确定删除?"
              onConfirm={() => handleDelete(record, dataSource)}
            >
              <a>删除</a>
            </Popconfirm>
          </Space>
        );
      },
    });
    setColumns(columnsValue);
  };
  // 改后这样写3
  const handleChange = (newlist) => {
    setDataSource(newlist);
    setDataSourceTemp(!DataSourceTemp);
  };
  return (
    <>
      <div style={headerSty}>
        <div style={{ marginLeft: "10px" }}>
          <UploadFile></UploadFile>
        </div>
      </div>
      <EditableProTable
        rowKey="key"
        headerTitle="数据列表"
        request={async () => ({
          data: [...dataSource],
        })}
        recordCreatorProps={
          position !== "hidden"
            ? {
                position: position,
                record: () => ({ key: (Math.random() * 1000000).toFixed(0) }),
              }
            : false
        }
        value={[...dataSource]}
        defaultData={[...dataSource]}
        onChange={handleChange} // 改后这样写4,关键这里要再更新数据
        columns={columns}
        bordered
        editable={{
          type: "multiple",
          editableKeys,
          onSave: async (rowKey, data, row) => {
            await waitTime(1000);
            setDataSource([...dataSource]);
          },
          onChange: setEditableRowKeys,
          onCancel: () => {
            // setIsedit(false);
          },
          onDelete: () => {
            handleDelete(delData);
          },
        }}
      ></EditableProTable>
    </>
  );
}
const mapStateToProps = ({ fileContent }) => {
  return {
    ...fileContent,
  };
};
export default connect(mapStateToProps)(FatherCmpt);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

# 📆 20210124

# 问题一

  1. 问题描述:react 开发,在componentDidMount中得到get请求的数据res,想在之后的事件中得到刚开始get请求的数据,但发现数据随着页面的数据变化了,得不到原始数据
  2. 原因:引用类型的赋值问题,使用深拷贝,这样创建的对象就会指向新的地址,当进行修改的时候,另一个属性值不变。
  3. 解决:
  state = {
    initData: {},
    cancelData: {},
  };
componentDidMount = () => {
  queryInitData().then((res) => {
    this.setState({
      initData: res,
      //  cancelData: res,//这种写法得不到开始的数据res
      cancelData: JSON.parse(JSON.stringify(res)), //深拷贝,想得到的是最初进入这个页面的值
    });
  });
};
...this.setState({initData: 其它数据});
handleCancel = () => {
  this.setState({
    initData: JSON.parse(JSON.stringify(this.state.cancelData)), //不然,这里的数据跟着变化
  });
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 问题二

  1. 问题描述:react 开发,数据已经更新,但视图没有更新,打印的时候发现,这个数据渲染了两次,第一次是上一次的数据,第二次是新的数据。

  2. 解决:每次都生成不同且唯一的key值。

  • key 相同,若组件属性有所变化,则 react 只更新组件对应的属性;没有变化则不更新。
  • key 值不同,则 react 先销毁该组件( 有状态组件的 componentWillUnmount 会执行 ),然后重新创建该组件( 有状态组件的 constructor 和 componentWillUnmount 都会执行 )。
// 每次都生成唯一的key值
<组件 key={+new Date() + Math.random()}><组件/>

1
2
3