如何根据不同的属性对React组件列表进行排序?

时间:2018-02-13 10:12:13

标签: reactjs redux

所以,这是我前端的代码片段。

{store.results.data.map( result =>
  <ResultItem 
    key={result.id}
    title={result.title}
    description={result.description}
    start_date={result.start_date}
    end_date={result.end_date}
    vendor_name={result.vendor.name}
    buyer_name={result.buyer.name}
    preview_file={result.preview_file}
    status={result.status}
  />
)}

基本上,我将Redux商店中的所有数据映射到ResultItems。我希望能够按ResultItemstitledescriptionstart_dateend_date和{{}等不同属性对vendor_name所有buyer_name进行排序{1}}。

关于如何做到这一点的任何想法?

6 个答案:

答案 0 :(得分:1)

首先,您应该知道几乎无法处理反应组件 - 这包括对它们进行排序。

其次,如果您有一个数组(比如arr)并且在其上调用.sort()方法,则数组将按就地排序,即{{ 1}}将被修改。

现在,您的问题的时间。在指出here时,您希望实现动态排序。这需要一些自定义compareFunction  知道如何根据对象比较对象。这是一个例子:

arr

以下是您的代码的外观:

arr = [
    {
        num: 1,
        text: 'z',
    },

    {
        num: 2,
        text: 'y'
    },

    {
        num: 3,
        text: 'x'
    },
];

const ASC = 'ascending';
const DSC = 'descending';

function sortByNum(a, b, order = ASC) {
    const diff = a.num - b.num;

    if (order === ASC) {
        return diff;
    }

    return -1 * diff;
}

function sortByText(a, b, order = ASC) {
    const diff = a.text.toLowerCase().localeCompare(b.text.toLowerCase());

    if (order === ASC) {
        return diff;
    }

    return -1 * diff;
}

console.log(arr.sort((a, b) => sortByNum(a, b, DSC)))
console.log(arr.sort((a, b) => sortByText(a, b, ASC)))

答案 1 :(得分:0)

您必须在执行地图部分之前对数据进行排序。例如,想象你想按id排序:

    {store.results.data.sort((a, b) => a.id - b.id).map( result =>
            <ResultItem key={result.id}
            title={result.title}
            description={result.description}
            start_date={result.start_date}
            end_date={result.end_date}
            vendor_name={result.vendor.name}
            buyer_name={result.buyer.name}
            preview_file={result.preview_file}
            status={result.status}
   />)}

答案 2 :(得分:0)

Lodash库可以达到这个目的。

{_.sortBy(store.results.data, ['status', 'start_date']).map( result =>
        <ResultItem key={result.id}
        title={result.title}
        description={result.description}
        start_date={result.start_date}
        end_date={result.end_date}
        vendor_name={result.vendor.name}
        buyer_name={result.buyer.name}
        preview_file={result.preview_file}
        status={result.status}

/&GT;)}

您可以在['status','start_date',...]中提供要排序的多个字段。

答案 3 :(得分:0)

如果您使用select来选择要排序的字段,则可以创建以下内容:

<select onChange={(e) => {
      props.dispatch(sortMyArray(e.target.value)) 
    }}>
      <option value="start_date">Start Date</option>
      <option value="title">Title</option>
      <option value="description">description</option>
    </select>

并在sort方法sortMyArray中,你可以这样做:

export default sortMyArray(sortBy){ 
     return myArray.sort((a, b) => {
    if (sortBy === 'start_date') {
      return a.start_date < b.start_date ? 1 : -1;
    }
  });
};

答案 4 :(得分:0)

我将创建一个Sort组件并像这样包装结果项:

<Sort by='title'>
{store.results.data.map( result =>
  <ResultItem 
    key={result.id}
    title={result.title}
    description={result.description}
    start_date={result.start_date}
    end_date={result.end_date}
    vendor_name={result.vendor.name}
    buyer_name={result.buyer.name}
    preview_file={result.preview_file}
    status={result.status}
  />
)}
</Sort>

// Note: The 'by' prop passed into <Sort> in my example is hardcoded by you can grab it from redux or set it when user selects something from a list. Also you can pass another prop to indicate whether to sort by ascending or descending order etc

然后,在Sort组件中,您可以访问诸如React.Children.toArray之类的结果项数组,并对数组使用sort方法,并将sort方法传递给'compare'函数。

// Sort.js

import React from 'react';

// Compare function needed by the Sort component
const compare =(a, b) => {
    // you can access the relevant property like this a.props[by]
// depending whether you are sorting by tilte or year, you can write a compare function here, 

  }

const Sort= ({children, by})=> {
If (!by) {
// If no 'sort by property' provided, return original list
return children
}
return React.Children.toArray(children).sort(compare)

}

上面的主要优点是您可以在其他任何地方使用Sort组件,并且可以使排序逻辑与映射到初始结果上完全分开。

答案 5 :(得分:0)

我用这个组件代码得到了这个:

/* eslint-disable react/jsx-no-useless-fragment */
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import './Sort.module.scss';

export interface SortProps {
  children: React.ReactNode;
  childType: string;
  by?: any;
  keyWith?: string;
}

// thx: https://stackoverflow.com/a/55996695/6200791
// thx: https://frontarm.com/james-k-nelson/passing-data-props-children/
// -------------------
export const Sort: React.FC<SortProps> = ({ children, childType, by, keyWith = "id" }) => {

  // ##################################################################################
  // # COMPARISON FUNCTION
  // ##################################################################################
  const compare = (aRaw: any, bRaw: any): any => {
    const a = aRaw.props[childType];
    const b = bRaw.props[childType];

    // Compare function needed by the Sort component
    // you can access the relevant property like this a.props[by]
    // depending whether you are sorting by tilte or year, you can write a compare function here, 
    if (!!a && !!b) {
      switch (by) {

        case "createdAt":
          return b[by] > a[by] ? 1 : -1;
          break;

        case "description":
          return a[by].localeCompare(b[by]);
          break;
      }
    }
  }
  // ##################################################################################
  // # /end COMPARISON FN
  // ##################################################################################

  if (!children) {
    return (<></>);
  }

  if (!by) {
    // If no 'sort by property' provided, return original list
    return (<>{children}</>);
  
  } else {
    // trying to workaround error: Each child in a list should have a unique "key" prop
    const elements: any[] = React.Children.toArray(children);
    const keyed: any[] = elements
      .sort(compare)
      .map((child, newIdx) => {
        return React.cloneElement(child, { key: (child as any)[keyWith], idx: newIdx });
      });
    return (<>{keyed}</>);
  }
}

export default Sort;

然后我使用如下(故事书故事):

import React from 'react';
import Sort from './Sort';

type CartModified = {
  description: string;
  id: number;
  name: string;
  createdAt: string;
}

export default {
  component: Sort,
  title: 'Sort',
};
const carts = [
  { id: 2, name: "2nd", createdAt: "2021-04-23T23:27:51.943Z", description: "d" },
  { id: 3, name: "3rd", createdAt: "2021-05-23T23:27:51.943Z", description: "b" },
  { id: 1, name: "1st", createdAt: "2021-03-23T23:27:51.943Z", description: "c" },
  { id: 4, name: "4th", createdAt: "2021-06-23T23:27:51.943Z", description: "a" },
] as CartModified[];

const TestItem: React.FC<{ c: CartModified }> = ({ c }) => {
  return <div>
      {c.name} # {c.id} - {c.createdAt} ({c.description})
  </div>;
}

// -------------------
export const withSortByCreatedAt = () => {
  return <Sort by="createdAt" childType="c" >
    {carts.map((c) => !c ? null : (
      <TestItem
        key={c.id}
        c={c}/>
    ))}
  </Sort>;
};


// -------------------
export const withSortByCategory = () => {
  return <Sort by="description" childType="c" >
    {carts.map((c) => !c ? null : (
      <TestItem
        key={c.id}
        c={c}/>
    ))}
  </Sort>;
};