首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在保持数据有序的同时继续接收数据?

如何在保持数据有序的同时继续接收数据?
EN

Stack Overflow用户
提问于 2019-09-10 13:17:31
回答 3查看 529关注 0票数 1

当用户单击表头(对表进行排序所需的)时,我正在处理此响应表排序,排序正在工作,但问题是,我每秒钟都通过SignalR集线器接收新数据,并将状态udata设置为新数据。当用户单击表头时,它会对表进行排序,但再次回到由新数据更改的新状态。并将排序表取消为未排序表。

是否有任何方法可以保持排序状态,并仍然接收数据?

我是新来的,任何帮助都会很感激

代码语言:javascript
复制
constructor() {
    super()
    this.state = {
      udata: [],
      sort: {
        column: null,
        direction: 'desc',
      },
    }
  }

  componentDidMount() {
    let connection = new signalR.HubConnectionBuilder()
      .withUrl('/signalserver')
      .build()

    connection
      .start()
      .then(function() {})
      .catch(function(err) {
        return console.error(err.toString())
      })
    connection.on(
      'APIChannel',
      function(data) {
        this.setState({udata: data})
      }.bind(this),
    )

    async function start() {
      try {
        await connection.start()
        console.log('connected')
      } catch (err) {
        console.log(err)
        setTimeout(() => start(), 5000)
      }
    }

    connection.onclose(async () => {
      await start()
    })
  }

  onSort(column) {
    return function(e) {
      let direction = this.state.sort.direction

      if (this.state.sort.column === column) {
        // Change the sort direction if the same column is sorted.
        direction = this.state.sort.direction === 'asc' ? 'desc' : 'asc'
      }

      // Sort ascending.
      const sortedData = this.state.udata.sort((a, b) => {
        if (column === 'appName') {
          // This sorts strings taking into consideration numbers in strings.
          // e.g., Account 1, Account 2, Account 10. Normal sorting would sort it Account 1, Account 10, Account 2.
          const collator = new Intl.Collator(undefined, {
            numeric: true,
            sensitivity: 'base',
          })

          return collator.compare(a.appName, b.appName)
        } else {
          return a.contractValue - b.contractValue
        }
      })

      // Reverse the order if direction is descending.
      if (direction === 'desc') {
        sortedData.reverse()
      }

      // Set the new state.
      this.setState({
        udata: sortedData,
        sort: {
          column,
          direction,
        },
      })
    }.bind(this) // Bind "this" again because the onSort function is returning another function.
  }

  renderItem(item, key) {
    const itemRows = [
      <tr onClick={clickCallback} key={'row-data-' + key}>
        <td>{item.appName}</td>
        <td>
          <h6 className="text-muted">
            <i
              className={
                'fa fa-circle text-c-' +
                (item.appState === 'STARTED' ? 'green' : 'red') +
                ' f-10 m-r-15'
              }
            />
            {item.appState}
          </h6>
        </td>
        <td>{item.spaceName}</td>
        <td>
          <h6 className="text-muted">{item.orgName}</h6>
        </td>
        <td>
          <h6 className="text-muted">
            {new Date(item.appUpdatedAt).toLocaleString()}
          </h6>
        </td>
      </tr>,
    ]

    return itemRows
  }

  render() {
    let allItemRows = []

    this.state.udata.forEach((item, key) => {
      const perItemRows = this.renderItem(item, key)
      allItemRows = allItemRows.concat(perItemRows)
    })

    return (
      <Aux>
        <Row>
          <Table hover responsive>
            <thead>
              <tr>
                <th className="sortable" onClick={this.onSort('appName')}>
                  {' '}
                  Account Name
                </th>
                <th> State</th>
                <th> Space</th>
                <th> Organization</th>
                <th className="sortable" onClick={this.onSort('appUpdatedAt')}>
                  {' '}
                  Updated At
                </th>
              </tr>
            </thead>
            <tbody> {allItemRows}</tbody>
          </Table>
        </Row>
      </Aux>
    )
  }

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-09-10 14:01:08

将函数的排序部分移动到新的a函数:

代码语言:javascript
复制
const sortData = (data, column, direction) => {
    // Sort ascending.
      const sortedData = data.sort((a, b) => {
        if (column === 'appName') {
          const collator = new Intl.Collator(undefined, {
            numeric: true,
            sensitivity: 'base',
          })

          return collator.compare(a.appName, b.appName)
        } else {
          return a.contractValue - b.contractValue
        }
      })

      // Reverse the order if direction is descending.
      if (direction === 'desc') {
        return sortedData.reverse()
      }
      return sortedData
}

在使用componentDidMount设置状态之前,可以在newData中使用该函数,也可以在onSort函数中使用该函数。

代码语言:javascript
复制
onSort(column) {
    return function(e) {
      let direction = this.state.sort.direction

      if (this.state.sort.column === column) {
        // Change the sort direction if the same column is sorted.
        direction = this.state.sort.direction === 'asc' ? 'desc' : 'asc'
      }

      // Sort ascending.
      const sortedData = this.sortData(this.state.udata, column, direction)

      // Set the new state.
      this.setState({
        udata: sortedData,
        sort: {
          column,
          direction,
        },
      })
    }.bind(this) // Bind "this" again because the onSort function is returning another function.
  }

componentDidMount:

代码语言:javascript
复制
componentDidMount() {
  // Code

   connection.on(
      'APIChannel',
      function(data) {
        let sortedData = []
        if (this.state.sort.column) {
         sortedData = this.sortData(data, this.state.sort.column, 
             this.state.sort.direction)
        } else {
         sortedData = data
        }

        this.setState({udata: sortedData})
      }.bind(this),
    )

   // Rest of the code
}

编辑:

代码语言:javascript
复制
import React, { Component } from "react";
import { Row, Col, Form, Card, Table, Tab, Nav } from "react-bootstrap";
import Aux from "../../hoc/_Aux";
import * as signalR from "@aspnet/signalr";

class Dashboard extends Component {
  constructor() {
    super();
    this.state = {
      udata: [],
      sysdata: [],
      expandedRows: [],
      user: "active",
      system: "",
      data: [],
      UserFilters: {
        appState: [],
        orgName: [],
        spaceName: []
      },
      SysFilters: {
        appState: []
      },
      intervalId: 0, //Scroll on top feature
      sort: {
        column: null,
        direction: "desc"
      }
    };
  }

  sortData = (data, column, direction) => {
    // Sort ascending.
    const sortedData = data.sort((a, b) => {
      if (column === 'appName') {
        const collator = new Intl.Collator(undefined, {
          numeric: true,
          sensitivity: 'base',
        })

        return collator.compare(a.appName, b.appName)
      } else {
        return a.contractValue - b.contractValue
      }
    })

    // Reverse the order if direction is descending.
    if (direction === 'desc') {
      return sortedData.reverse()
    }
    return sortedData
  };

  componentDidMount() {
    let connection = new signalR.HubConnectionBuilder()
      .withUrl("/signalserver")
      .build();

    connection
      .start()
      .then(function () { })
      .catch(function (err) {
        return console.error(err.toString());
      });

    connection.on(
      "SBUserBrodcasting",
      function (data) {
        let sortedData = [];
        if (this.state.sort.column) {
          sortedData = this.sortData(
            data,
            this.state.sort.column,
            this.state.sort.direction
          );
        } else {
          sortedData = data;
        }
        this.setState({ udata: sortedData });
      }.bind(this)
    );

    connection.on(
      "SBSystemBrodcasting",
      function (data) {
        this.setState({ sysdata: data });
      }.bind(this)
    );

    async function start() {
      try {
        await connection.start();
        console.log("connected");
      } catch (err) {
        console.log(err);
        setTimeout(() => start(), 5000);
      }
    }

    connection.onclose(async () => {
      await start();
    });
  }

    onSort(column) {
      return function (e) {
        let direction = this.state.sort.direction;

        if (this.state.sort.column === column) {
          // Change the sort direction if the same column is sorted.
          direction = this.state.sort.direction === "asc" ? "desc" : "asc";
        }

        // Sort ascending.
        const sortedData = this.sortData(this.state.udata, column, direction);

        // Set the new state.
        this.setState({
          udata: sortedData,
          sort: {
            column,
            direction
          }
        });
      }.bind(this); // Bind "this" again because the onSort function is returning another function.
    }

  scrollStep() {
    if (window.pageYOffset === 0) {
      clearInterval(this.state.intervalId);
    }
    window.scroll(0, window.pageYOffset - this.props.scrollStepInPx);
  }

  scrollToTop() {
    let intervalId = setInterval(
      this.scrollStep.bind(this),
      this.props.delayInMs
    );
    this.setState({ intervalId: intervalId });
  }

  FilterUserArray = (array, UserFilters) => {
    let getValue = value =>
      typeof value === "string" ? value.toUpperCase() : value;

    const filterKeys = Object.keys(UserFilters);
    return array.filter(item => {
      // validates all filter criteria
      return filterKeys.every(key => {
        // ignores an empty filter
        if (!UserFilters[key].length) return true;
        return UserFilters[key].find(
          filter => getValue(filter) === getValue(item[key])
        );
      });
    });
  };

  FilterSysArray = (array, SysFilters) => {
    let getValue = value =>
      typeof value === "string" ? value.toUpperCase() : value;

    const filterKeys = Object.keys(SysFilters);
    return array.filter(item => {
      // validates all filter criteria
      return filterKeys.every(key => {
        // ignores an empty filter
        if (!SysFilters[key].length) return true;
        return SysFilters[key].find(
          filter => getValue(filter) === getValue(item[key])
        );
      });
    });
  };

  HandleRowClick(rowId) {
    const currentExpandedRows = this.state.expandedRows;
    const isRowCurrentlyExpanded = currentExpandedRows.includes(rowId);
    const newExpandedRows = isRowCurrentlyExpanded
      ? currentExpandedRows.filter(id => id !== rowId)
      : currentExpandedRows.concat(rowId);
    this.setState({ expandedRows: newExpandedRows });
  }

  SpaceRenderFilterList(item, key) {
    const itemRows = [
      <li key={"li-data-" + key}>
        <Form.Check
          custom
          type="checkbox"
          value={item}
          id={"SBSpace-" + item}
          label={item}
          onChange={this.UserAppSpaceFilter.bind(this)}
        />
      </li>
    ];
    return itemRows;
  }

  OrgRenderFilterList(item, key) {
    const itemRows = [
      <li key={"li-data-" + key}>
        <Form.Check
          custom
          type="checkbox"
          value={item}
          id={"SBOrg-" + item}
          label={item}
          onChange={this.UserAppOrgFilter.bind(this)}
        />
      </li>
    ];
    return itemRows;
  }

  RenderItem(item, key) {
    const clickCallback = () => this.HandleRowClick(key);
    const itemRows = [
      <tr onClick={clickCallback} key={"row-data-" + key}>
        <td>{item.appName}</td>
        <td>
          <h6 className="text-muted">
            <i
              className={
                "fa fa-circle text-c-" +
                (item.appState === "STARTED" ? "green" : "red") +
                " f-10 m-r-15"
              }
            />
            {item.appState}
          </h6>
        </td>
        <td>{item.spaceName}</td>
        <td>
          <h6 className="text-muted">{item.orgName}</h6>
        </td>
        <td>
          <h6 className="text-muted">
            {new Date(item.appUpdatedAt).toLocaleString()}
          </h6>
        </td>
      </tr>
    ];

    if (this.state.expandedRows.includes(key)) {
      itemRows.push(
        <tr key={"row-expanded-" + key}>
          <td colSpan="6">
            <Card className="card-event">
              <Card.Body>
                <div className="row align-items-center justify-content-center">
                  <div className="col">
                    <h5 className="m-0">Upcoming Event</h5>
                  </div>
                  <div className="col-auto">
                    <label className="label theme-bg2 text-white f-14 f-w-400 float-right">
                      34%
                    </label>
                  </div>
                </div>
                <h2 className="mt-2 f-w-300">
                  45<sub className="text-muted f-14">Competitors</sub>
                </h2>
                <h6 className="text-muted mt-3 mb-0">
                  You can participate in event{" "}
                </h6>
                <i className="fa fa-angellist text-c-purple f-50" />
              </Card.Body>
            </Card>
          </td>
        </tr>
      );
    }

    return itemRows;
  }

  onClickfn = () => {
    this.setState({ user: "active", system: "inactive" });
  };

  onClickfnsys = () => {
    this.setState({ user: "inactive", system: "active" });
  };

  UserAppStateFilter(e) {
    let index;
    // current array of options
    const options = this.state.UserFilters.appState;
    // check if the check box is checked or unchecked
    if (e.target.checked) {
      // add the numerical value of the checkbox to options array
      options.push(e.target.value);
    } else {
      // or remove the value from the unchecked checkbox from the array
      index = options.indexOf(e.target.value);
      options.splice(index, 1);
    }
    // update the state with the new array of options
    this.setState({
      UserFilters: { ...this.state.UserFilters, appState: options }
    });
  }

  UserAppSpaceFilter(e) {
    let index;
    // current array of options
    const options = this.state.UserFilters.spaceName;
    // check if the check box is checked or unchecked
    if (e.target.checked) {
      // add the numerical value of the checkbox to options array
      options.push(e.target.value);
    } else {
      // or remove the value from the unchecked checkbox from the array
      index = options.indexOf(e.target.value);
      options.splice(index, 1);
    }
    // update the state with the new array of options
    this.setState({
      UserFilters: { ...this.state.UserFilters, spaceName: options }
    });
  }

  UserAppOrgFilter(e) {
    let index;
    // current array of options
    const options = this.state.UserFilters.orgName;
    // check if the check box is checked or unchecked
    if (e.target.checked) {
      // add the numerical value of the checkbox to options array
      options.push(e.target.value);
    } else {
      // or remove the value from the unchecked checkbox from the array
      index = options.indexOf(e.target.value);
      options.splice(index, 1);
    }
    // update the state with the new array of options
    this.setState({
      UserFilters: { ...this.state.UserFilters, orgName: options }
    });
  }

  SysAppStateFilter(e) {
    let index;
    // current array of options
    const options = this.state.SysFilters.appState;
    // check if the check box is checked or unchecked
    if (e.target.checked) {
      // add the numerical value of the checkbox to options array
      options.push(e.target.value);
    } else {
      // or remove the value from the unchecked checkbox from the array
      index = options.indexOf(e.target.value);
      options.splice(index, 1);
    }
    // update the state with the new array of options
    this.setState({
      SysFilters: { ...this.state.SysFilters, appState: options }
    });
  }

  render() {
    let Spacefilterlist = [];

    Array.from(new Set(this.state.udata.map(item => item.spaceName))).forEach(
      (item, key) => {
        const perItemRows = this.SpaceRenderFilterList(item, key);
        Spacefilterlist = Spacefilterlist.concat(perItemRows);
      }
    );

    let Orgfilterlist = [];

    Array.from(new Set(this.state.udata.map(item => item.orgName))).forEach(
      (item, key) => {
        const perItemRows = this.OrgRenderFilterList(item, key);
        Orgfilterlist = Orgfilterlist.concat(perItemRows);
      }
    );

    let allItemRows = [];

    this.FilterUserArray(this.state.udata, this.state.UserFilters).forEach(
      (item, key) => {
        const perItemRows = this.RenderItem(item, key);
        allItemRows = allItemRows.concat(perItemRows);
      }
    );

    let sysallItemRows = [];

    this.FilterSysArray(this.state.sysdata, this.state.SysFilters).forEach(
      (item, key) => {
        const perItemRows = this.RenderItem(item, key);
        sysallItemRows = sysallItemRows.concat(perItemRows);
      }
    );

    return (
      <Aux>
        <Row>
          <Col sm={12}>
            <Tab.Container defaultActiveKey="user">
              <Row>
                <Col sm={2}>
                  <Nav variant="pills" className="flex-column">
                    <Nav.Item>
                      <Nav.Link eventKey="user" onClick={this.onClickfn}>
                        User
                      </Nav.Link>
                    </Nav.Item>
                    <Nav.Item>
                      <Nav.Link eventKey="system" onClick={this.onClickfnsys}>
                        System
                      </Nav.Link>
                    </Nav.Item>
                  </Nav>
                  <br />
                  <Card
                    style={{
                      display: this.state.user === "active" ? "" : "none"
                    }}
                  >
                    <Tab.Pane eventKey="user">
                      <Card.Header>
                        <Card.Title as="h5">Filters</Card.Title>
                      </Card.Header>
                      <Card.Body>
                        <h6>By State</h6>
                        <hr />
                        <ul className="list-inline m-b-0">
                          <Form.Group onReset={this.handleFormReset}>
                            <li>
                              <Form.Check
                                custom
                                type="checkbox"
                                id="checkbox1"
                                value="STARTED"
                                label="STARTED"
                                onChange={this.UserAppStateFilter.bind(this)}
                              />
                            </li>
                            <li>
                              <Form.Check
                                custom
                                type="checkbox"
                                id="checkbox2"
                                value="STOPPED"
                                label="STOPPED"
                                onChange={this.UserAppStateFilter.bind(this)}
                              />
                            </li>
                          </Form.Group>
                        </ul>
                        <h6>By Space</h6>
                        <hr />
                        <ul className="list-inline m-b-0">
                          <Form.Group>{Spacefilterlist}</Form.Group>
                        </ul>
                        <h6>By Organization</h6>
                        <hr />
                        <ul className="list-inline m-b-0">
                          <Form.Group>{Orgfilterlist}</Form.Group>
                        </ul>
                      </Card.Body>
                    </Tab.Pane>
                  </Card>
                  <Card>
                    <Tab.Pane
                      eventKey="system"
                      style={{
                        display: this.state.system === "active" ? "" : "none"
                      }}
                    >
                      <Card.Header>
                        <Card.Title as="h5">Filters</Card.Title>
                      </Card.Header>
                      <Card.Body>
                        <h6>By State</h6>
                        <hr />
                        <ul className="list-inline m-b-0">
                          <Form.Group>
                            <li>
                              <Form.Check
                                custom
                                type="checkbox"
                                id="chec1"
                                value="STARTED"
                                label="STARTED"
                                onChange={this.SysAppStateFilter.bind(this)}
                              />
                            </li>
                            <li>
                              <Form.Check
                                custom
                                type="checkbox"
                                id="chec2"
                                value="STOPPED"
                                label="STOPPED"
                                onChange={this.SysAppStateFilter.bind(this)}
                              />
                            </li>
                          </Form.Group>
                        </ul>
                      </Card.Body>
                    </Tab.Pane>
                  </Card>
                </Col>
                <Col sm={10}>
                  <Tab.Content>
                    <Tab.Pane eventKey="user">
                      <Table hover responsive>
                        <thead>
                          <tr>
                            <th
                              className="sortable"
                              onClick={this.onSort("appName")}
                            >
                              Account Name
                            </th>
                            <th>State</th>
                            <th>Space</th>
                            <th>Organization</th>
                            <th
                              className="sortable"
                              onClick={this.onSort("appUpdatedAt")}
                            >
                              Updated At
                            </th>
                          </tr>
                        </thead>
                        <tbody>{allItemRows}</tbody>
                      </Table>
                    </Tab.Pane>
                    <Tab.Pane eventKey="system">
                      <Table hover responsive>
                        <thead>
                          <tr>
                            <th>App Name</th>
                            <th>State</th>
                            <th>Space</th>
                            <th>Organization</th>
                            <th>Updated At</th>
                          </tr>
                        </thead>
                        <tbody>{sysallItemRows}</tbody>
                      </Table>
                    </Tab.Pane>
                  </Tab.Content>
                </Col>
              </Row>
            </Tab.Container>
          </Col>
          <button
            id="myBtn"
            title="Back to top"
            className="scroll"
            onClick={() => {
              this.scrollToTop();
            }}
          >
            <span className="feather icon-chevron-up" />
          </button>
        </Row>
      </Aux>
    );
  }
}

export default Dashboard;
票数 1
EN

Stack Overflow用户

发布于 2019-09-10 13:28:42

使用父组件执行请求,并将未排序的值和排序顺序值传递给子组件。子组件(最有可能是表组件)将根据排序顺序值显示数据。

当前,每次更改状态值时,组件都会被挂载。

票数 0
EN

Stack Overflow用户

发布于 2019-09-10 13:57:22

添加一个名为componentWillReceiveProps(nextProps)的生命周期方法,或者您也可以使用static getDerivedStateFromProps(props, state)在该方法中执行排序,这样当新数据可用时,它将自动与原来的数据一起排序。因此,所有其他代码都保持不变,新的数据在排序中占据了正确的位置。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57871695

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档