首页 > 解决方案 > 将 Hooks 与 Redux 一起使用——不好的做法?

问题描述

我正在尝试实现一个排序表,如 Semantic UI Docs 中所示。

https://react.semantic-ui.com/collections/table/#variations-sortable

我在我的项目中使用 redux,并且对如何实现排序表和搜索输入功能感到困惑。

在页面加载时,我将所有数据存储在称为棒球的状态中。我还有一个 cardsToShow 状态,如果用户正在搜索某些东西,它会更新,由 searchCards 函数触发。cardToShow 状态是我用来显示我的数据的状态。

const mapStateToProps = state => {
  return {
    baseball: state.baseball,
    cardsToShow: searchCards(state)
  };
};

const searchCards = ({ baseball, search }) => {
  return search
    ? baseball.filter(a =>
        a.title[0].toLowerCase().includes(search.toLowerCase())
      )
    : baseball;
};

在 Semantic UI/Lodash 示例中,它们会在用户单击列时更新和排序数据状态。

我尝试使用列、方向和过滤数据字段的一些状态挂钩来复制它。

const Cards = props => {
  const [column, setColumn] = useState(null);
  const [direction, setDirection] = useState(null);
  const [filteredData, setData] = useState(props.cardsToShow);

  const handleSort = clickedColumn => {
    if (column !== clickedColumn) {
      setColumn(clickedColumn);
      setData(_.sortBy(filteredData, [clickedColumn]));
      setDirection("ascending");
      return;
    }

    setData(_.sortBy(filteredData.reverse()));
    direction === "ascending"
      ? setDirection("descending")
      : setDirection("ascending");
  };

这也是我的列标题的样子:

  <Table.HeaderCell
                    sorted={column === "title" ? direction : null}
                    onClick={handleSort("title")}
                  >
                    Card Title
                  </Table.HeaderCell>

首先,我在上面的代码中收到“重新渲染过多”错误,这是一个问题。但主要问题是我现在有一个正在更新的过滤数据字段......但我还有其他状态卡显示。

我知道我在这里所做的任何事情都是错误的,但很想知道是否有人对如何最好地完成这一点有任何指导。使用这样的钩子以及拥有一个保存全局状态的 redux 存储是否可以接受?或者我应该以某种方式为我想要做的排序创建另一个减速器?谢谢。

---编辑---更新了下面的组件

import React, { useState } from "react";
import Search from "./Search";
import TimeAgo from "react-timeago";
import { useSelector} from "react-redux";
import { Table } from "semantic-ui-react";
import _ from "lodash";
// import { useField } from "../hooks";

const searchCards = ({ baseball, search }) => {
  return search
    ? baseball.filter(a =>
        a.title[0].toLowerCase().includes(search.toLowerCase())
      )
    : baseball;
};

const Cards = () => {
  const baseball = useSelector(state => state.baseball);
  const search = useSelector(state => state.search);
  const cardsToShow = searchCards(baseball, search);
  const [column, setColumn] = useState(null);
  const [direction, setDirection] = useState(null);
  const [filteredData, setData] = useState(cardsToShow);

  const handleSort = clickedColumn => {
    if (column !== clickedColumn) {
      setColumn(clickedColumn);
      setData(_.sortBy(filteredData, [clickedColumn]));
      setDirection("ascending");
      return;
    }

    setData(_.sortBy(filteredData.reverse()));
    direction === "ascending"
      ? setDirection("descending")
      : setDirection("ascending");
  };

  return (
    <>
      <div>
        <Search />
        <h3>Vintage Card Search</h3>
        <Table sortable celled fixed striped>
          <Table.Header>
            <Table.Row>
              <Table.HeaderCell
                sorted={column === "title" ? direction : null}
                onClick={handleSort("title")}
              >
                Card Title
              </Table.HeaderCell>
              <Table.HeaderCell># Bids</Table.HeaderCell>
              <Table.HeaderCell>Watchers</Table.HeaderCell>
              <Table.HeaderCell>Price</Table.HeaderCell>
              <Table.HeaderCell>Time Left</Table.HeaderCell>
            </Table.Row>
          </Table.Header>
          <Table.Body>
            {filteredData.map(card => (
              <>
                <Table.Row key={card.id}>
                  <Table.Cell>{card.title}</Table.Cell>
                  <Table.Cell>
                    {card.sellingStatus[0].bidCount
                      ? card.sellingStatus[0].bidCount
                      : 0}
                  </Table.Cell>
                  <Table.Cell>
                    {card.listingInfo[0].watchCount
                      ? card.listingInfo[0].watchCount
                      : 0}
                  </Table.Cell>
                  <Table.Cell>
                    $
                    {card.sellingStatus &&
                      card.sellingStatus[0].currentPrice[0]["__value__"]}
                  </Table.Cell>
                  <Table.Cell>
                    <TimeAgo
                      date={new Date(
                        card.listingInfo && card.listingInfo[0].endTime
                      ).toLocaleDateString()}
                    />
                  </Table.Cell>
                </Table.Row>
              </>
            ))}
          </Table.Body>
        </Table>
      </div>
    </>
  );
};

export default Cards;

标签: javascriptreactjsreact-reduxlodashreact-hooks

解决方案


而不是像以前那样使用 Redux,请以这种方式在 hooks 中尝试新的 Redux 实现:

import React, {useState} from "react";
import {useSelector } from "react-redux";

const searchCards = (baseball, search) => {
  return search
    ? baseball.filter(a =>
        a.title[0].toLowerCase().includes(search.toLowerCase())
      )
    : baseball;
};

export const Cards = () => {
  const baseball = useSelector(state => state.baseball);
  const search = useSelector(state => state.search);
  const cardsToShow = searchCards(baseball, search);
  const [column, setColumn] = useState(null);
  const [direction, setDirection] = useState(null);
  const [filteredData, setData] = useState(cardsToShow);

  const handleSort = clickedColumn => {
    if (column !== clickedColumn) {
      setColumn(clickedColumn);
      setData(_.sortBy(filteredData, [clickedColumn]));
      setDirection("ascending");
      return;
    }

    setData(_.sortBy(filteredData.reverse()));
    direction === "ascending"
      ? setDirection("descending")
      : setDirection("ascending");
  };

  return {filteredData, handleSort};
};

从你解释你想要实现的内容来看,我发现你需要导出filteredData元素(显示已过滤和排序的棒球卡)和handleSort能够触发Table组件更改的方法。我认为您不需要再次将过滤和排序的元素存储在 Redux 中。reselect如果您想这样做并提高性能,使用和记忆选择器就足够了。


推荐阅读