ReactJS-如何使用useCallback,useMemo优化性能

时间:2019-12-15 17:53:51

标签: reactjs react-hooks

我使用了约150个输入的表,如何避免不必要的重新渲染?

示例:

import React, { useState, forwardRef } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, Input, Form, Button } from "antd";

const initData = () => {
  const data = [];
  for (let i = 0; i < 300; i++) {
    data.push({
      key: i,
      name: `King ${i}`,
      age: 32,
      address: `London, Park Lane no. ${i}`
    });
  }

  return data;
};

function TableComponent({ value }, ref) {
  const [data, setData] = useState(value);

  const handleChange = (value, index) => {
    const newData = [...data];
    data[index].name = value;
    setData(newData);
  };

  const columns = [
    {
      title: "Name",
      dataIndex: "name",
      width: 300,
      render: (text, record, index) => (
        <Input
          value={text}
          onChange={({ target: { value } }) => handleChange(value, index)}
        />
      )
    },
    {
      title: "Age",
      dataIndex: "age",
      width: 150
    },
    {
      title: "Address",
      dataIndex: "address"
    }
  ];

  return (
    <Table ref={ref} columns={columns} dataSource={data} pagination={false} />
  );
}

TableComponent = forwardRef(TableComponent);

class Demo 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 layout="inline" onSubmit={this.handleSubmit}>
        <Form.Item>
          {getFieldDecorator("table", {
            initialValue: initData()
          })(<TableComponent />)}
        </Form.Item>
        <Form.Item>
          <Button type="primary" htmlType="submit">
            Submit
          </Button>
        </Form.Item>
      </Form>
    );
  }
}

const WrappedDemo = Form.create({ name: "customized_form_controls" })(Demo);

ReactDOM.render(<WrappedDemo />, document.getElementById("container"));

在线演示:https://codesandbox.io/s/ecstatic-curran-zngwu

我发现了如何使用useCallback,useMemo解决此问题,我尝试了很多次但都失败了,您可以指导我吗?

我尝试了下面的表格,但是没有用:https://codesandbox.io/s/wild-cherry-ue46i

1 个答案:

答案 0 :(得分:1)

您需要为组件React.memo()和状态操作useCallback

import React, { useState, forwardRef, useCallback } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, Input, Form, Button } from "antd";

const initData = () => {
  const data = [];
  for (let i = 0; i < 300; i++) {
    data.push({
      key: i,
      name: `King ${i}`,
      age: 32,
      address: `London, Park Lane no. ${i}`
    });
  }

  return data;
};

const CustomInput = React.memo(({ value, index, handleChange }) => (
  <span>
    {console.log("Rendered!")}
    <Input
      value={value}
      index={index}
      onChange={({ target: { value } }) => handleChange(value, index)}
    />
  </span>
));

function TableComponent({ value = {}, onChange }, ref) {
  const [data, setData] = useState(value);

  const triggerChange = useCallback(
    changedValue => {
      if (onChange) {
        setData(changedValue);
        onChange(changedValue);
      }
    },
    [onChange]
  );

  const handleChange = useCallback(
    (value, index) => {
      data[index].name = value;
      triggerChange(data);
    },
    [triggerChange, data]
  );

  const columns = [
    {
      title: "Name",
      dataIndex: "name",
      width: 300,
      render: (text, record, index) => (
        <CustomInput value={text} index={index} handleChange={handleChange} />
      )
    },
    {
      title: "Age",
      dataIndex: "age",
      width: 150
    },
    {
      title: "Address",
      dataIndex: "address"
    }
  ];

  return (
    <Table ref={ref} columns={columns} dataSource={data} pagination={false} />
  );
}

TableComponent = forwardRef(TableComponent);

class Demo 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 layout="inline" onSubmit={this.handleSubmit}>
        <Form.Item>
          {getFieldDecorator("table", {
            initialValue: initData()
          })(<TableComponent />)}
        </Form.Item>
        <Form.Item>
          <Button type="primary" htmlType="submit">
            Submit
          </Button>
        </Form.Item>
      </Form>
    );
  }
}

const WrappedDemo = Form.create({ name: "customized_form_controls" })(Demo);

ReactDOM.render(<WrappedDemo />, document.getElementById("container"));

https://codesandbox.io/s/patient-sunset-8by5s