需要获取所有子组件实例的所有值,并在parents方法中使用:ReactJS

Need to get all the values of all the child component instances and use it in parents method: ReactJS

我有一个 table(react-table) 应用列级别过滤的场景。我已将其提取为单独的组件(DropdDown 组件),并且可以将其附加到任何列。我在父组件中维护一个方法,它获取所有值的并集,即所有下拉列表的选定值,然后应用服务器端过滤。

现在的挑战是,如何在父组件方法中获取此合并值?

此 DropDown 组件具有关于该列的唯一值列表,有一个应用按钮,它应用服务器端过滤。现在,如果我跳到另一列,我需要获取先前检查的值以及当前值。

里面handleSetData()过滤逻辑写好了,我需要从DropDown组件中获取数据。每次我在列过滤器上单击“应用”时,我还需要获取之前检查过的值。

谁能帮我解决这个问题:

代码沙箱:https://codesandbox.io/s/quizzical-glitter-np8iw

应用组件

import * as React from "react";
import { render } from "react-dom";
import ReactTable from "react-table";
import "./styles.css";
import "react-table/react-table.css";
import DropDownComponent from "./DropDown";
interface IState {
  data: {}[];
  columns: {}[];
}

interface IProps {}

export default class App extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      data: [
        { firstName: "aaaaa", status: "Pending", visits: 155 },
        { firstName: "aabFaa", status: "Pending", visits: 155 },
        { firstName: "adaAAaaa", status: "Approved", visits: 1785 },
        { firstName: "aAaaaa", status: "Approved", visits: 175 },
        { firstName: "adaSaaa", status: "Cancelled", visits: 165 },
        { firstName: "aaaaa", status: "Cancelled", visits: 157 },
        { firstName: "aaaaa", status: "Approved", visits: 153 },
        { firstName: "aaaaa", status: "Pending", visits: 155 }
      ],
      columns: []
    };
  }

  handleSetState = (columns: any) => {
    this.setState({ columns });
  };

  handleSetData = (value: any) => {
    console.log(value); // Here filtering logic is written, I need to get the data from DropDown Component. Everytime I click on Apply on a column filter, I need to get the previously checked values as well
  };

  componentDidMount() {
    let columns = [
      {
        Header: () => (
          <div>
            <div style={{ position: "absolute", marginLeft: "10px" }}>
              <DropDownComponent
                data={this.state.data}
                handleSetData={this.handleSetData}
                param="firstName"
              />
            </div>
            <span>First Name</span>
          </div>
        ),
        accessor: "firstName",
        sortable: false,
        show: true,
        displayValue: " First Name"
      },
      {
        Header: () => (
          <div>
            <div style={{ position: "absolute", marginLeft: "10px" }}>
              <DropDownComponent
                data={this.state.data}
                handleSetData={this.handleSetData}
                param="status"
              />
            </div>
            <span>Status</span>
          </div>
        ),
        accessor: "status",
        sortable: false,
        show: true,
        displayValue: " Status "
      },
      {
        Header: "Visits",
        accessor: "visits",
        sortable: false,
        show: true,
        displayValue: " Visits "
      }
    ];
    this.setState({ columns });
  }

  render() {
    const { data, columns } = this.state;
    return (
      <div>
        <ReactTable
          data={data}
          columns={columns}
          defaultPageSize={10}
          className="-striped -highlight"
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

下拉组件

import * as React from "react";
import { Button, Checkbox, Icon } from "semantic-ui-react";
interface IProps {
  data: {}[];
  handleSetData(arr: any): void;
  param: string;
}
interface IState {
  showList: boolean;
  optionsArr: {}[];
  originalState: {}[];
}

export default class DropDownComponent extends React.Component<IProps, IState> {
  constructor(props: any) {
    super(props);
    this.state = {
      showList: false,
      optionsArr: [],
      originalState: []
    };
  }

  toggleList = () => {
    this.setState(prevState => ({ showList: !prevState.showList }));
  };

  handleItemClick = (event: React.FormEvent<HTMLInputElement>, data: any) => {
    const index = this.state.optionsArr.findIndex(
      (item: any) => item.text === data.name
    );
    const optionsArr = this.state.optionsArr.map((prevState: any, i: any) =>
      i === index
        ? {
            key: prevState.key,
            text: prevState.text,
            checked: !prevState.checked
          }
        : prevState
    );
    this.setState({ optionsArr });
  };

  submitSelection = () => {
    console.log(this.state.optionsArr.filter((item: any) => item.checked)); // This gives me selecte ones
    let checkedValues: any = this.state.optionsArr.filter(
      (item: any) => item.checked
    );
    this.setState({ originalState: this.state.optionsArr }, () =>
      this.props.handleSetData(checkedValues)
    );
  };

  componentDidMount() {
    if (this.props.data) {
      let arr = this.props.data;
      let uniqueValues = Array.from(
        new Set(arr.map((arr: any) => arr[this.props.param]))
      );
      var optionsArr = [];
      for (let i = 0; i < uniqueValues.length; i++) {
        var options: any = {};
        options["key"] = uniqueValues[i];
        options["text"] = uniqueValues[i];
        options["checked"] = false;
        optionsArr.push(options);
      }
      this.setState({ optionsArr: optionsArr, originalState: optionsArr });
    }
  }

  clearSelection = (event: any) => {
    // Push it to previous state, before cancel was clicked
    this.setState({ showList: false, optionsArr: this.state.originalState });
  };

  render() {
    let { showList } = this.state;
    let visibleFlag: string;
    if (showList === true) visibleFlag = "visible";
    else visibleFlag = "";
    return (
      <div>
        <div style={{ position: "absolute" }}>
          <div
            className={
              "ui scrolling dropdown column-settings customized " +
              visibleFlag +
              " " +
              this.props.menuDirection
            }
          >
            <Icon className="filter" onClick={this.toggleList} />
              {this.state.optionsArr.length > 0 ? (
                <>
                  <div className="menu-item-holder">
                    {this.state.optionsArr.map((item: any, i: number) => (
                      <div className="menu-item" key={i}>
                        <Checkbox
                          name={item.text}
                          onChange={this.handleItemClick}
                          checked={item.checked}
                          label={item.text}
                        />
                      </div>
                    ))}
                  </div>
                  <div className="menu-btn-holder">
                    <Button size="small" onClick={this.submitSelection}>
                      Apply
                    </Button>
                    <Button size="small" onClick={this.clearSelection}>
                      Cancel
                    </Button>
                  </div>
                </>
              ) : (
                ""
              )}
            </div>
          </div>
        </div>
      </div>
    );
  }
}

我修改了你的DropDown组件。我让它收到一个项目列表来生成复选框。与其将整个数据对象发送到 DropDown 组件,我认为向它们发送一个就绪列表更有意义,Main 组件应该生成正确的数据结构(我没有这样做,你必须创建那些函数)。在组件中,我创建了三个状态来管理组件。

Obs:我删除了打字稿以提高速度。 condesandbox