【问题标题】:React/Redux - Adding a sort or filter feature to one componentReact/Redux - 向一个组件添加排序或过滤功能
【发布时间】:2021-02-21 19:00:48
【问题描述】:

我构建了一个 react-redux 应用程序,它从 Rails API 获取评论列表 - 我真的想添加按字母升序/降序对评论列表进行排序的功能,但我不知道从哪里开始.

我是否需要添加我希望如何将此列表排序到状态,然后添加新操作才能执行此操作?或者有没有更简单的方法可以将它添加到显示评论列表的组件中?

如果可能的话,我会喜欢精确的代码示例,因为我真的不知道如何开始以及在哪里可以完成。

./components/reviews/ReviewsList.js

import React from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'

const ReviewList = props => {
  const reviewCards = props.reviews.length > 0 ?
    props.reviews.map(r => (
    <div>
    <br></br>
      <p key={r.id}><Link className="App-link" to={`/app/v1/reviews/${r.id}`}>{r.attributes.title}</Link>
      </p>
    </div>)) :
    null


  return reviewCards
}
const mapStateToProps = state => {
  return {
    reviews: state.reviews.reviews
  }
}

export default connect(mapStateToProps)(ReviewList)

App.js

import React from 'react';
import './App.css';
import ReviewsContainer from './containers/ReviewsContainer';
import ReviewList from './components/reviews/ReviewList'
import NewReviewForm from './components/reviews/NewReviewForm'
import Review from './components/reviews/Review'
import Header from './components/Header'
import Home from './components/Home'
import Footer from './components/Footer'
import { Switch, Route, withRouter } from 'react-router-dom'
import { connect } from 'react-redux';

class App extends React.Component {

  render(){
    const { reviews } = this.props
  return (
    <div className="App">
      <Header />
      <ReviewsContainer />
      <Switch>
        {/* Route renders appropriate components with the link path */}
      <Route exact path='/' component={Home}></Route> 
      <Route exact path='/app/v1/reviews' component={ReviewList}></Route>
      <Route exact path='/app/v1/reviews/new' component={NewReviewForm}/>
      <Route exact path='/app/v1/reviews/:id' render={props => {
        const review = reviews.find(review => review.id === props.match.params.id )
          return <Review review={review} {...props}/>
        }
        // above renders the specific Review URL to the appropriate selection -
      }/>
      </Switch>
      <br></br>
      <Footer />
    </div>
  );
  }
}

const mapStateToProps = state => {
  return ({
    reviews: state.reviews.reviews
  })
}
export default withRouter(connect(mapStateToProps)(App))

store.js

import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import reviews from './reducers/reviewReducer'
import newReviewForm from './reducers/newReviewForm'
import thunk from 'redux-thunk'

const reducers = combineReducers({
    reviews,
    newReviewForm
  })
  
  const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
  const store = createStore(reducers, composeEnhancer(applyMiddleware(thunk)))

  export default store

如果您还想查看其他代码,请告诉我。

【问题讨论】:

  • 您希望对评论的哪个属性进行排序?
  • 标题 - 这是评论列表当前显示的内容

标签: reactjs redux react-redux


【解决方案1】:

根据您帖子的措辞,我假设props.reviews 包含整个评论列表,而不仅仅是第一页,并且我们不会因为排序而显示不同的子集。如果是这样的话,那么我的建议是保持对redux的排序,在组件本身通过local state或者react router来处理。

当地国家

这取决于你想为你的状态使用什么格式,因为有多种方法是有意义的。

这里我们保存一个string"asc""desc"

const [order, setOrder] = useState("asc");

我们在这里保存boolean。如果是true,则顺序为降序,如果为false,则为升序。

const [isDesc, setIsDesc] = useState(false);

如果你想支持按title以外的属性排序,你可以使用除顺序之外的第二个状态:

const [sortBy, setSortBy] = useState("title");

路由器变量

使用 URL 查询(类似于 "/app/v1/reviews/?sort=title&amp;order=asc")通过 react-router 控制排序也可能有意义。您可以在 react-router docs 中查看该方法的示例。

Lodash 排序

Lodash 具有 sortByreverse 方法,可以非常轻松地对评论对象数组进行排序。

const sorted = _.sortBy(props.reviews, 'attributes.title');
const reviews = order === "desc" ? _.reverse(sorted) : sorted;

纯JS排序

如果你不依赖包,你可以将custom compare function using 传递给内置的数组排序方法。由于sort() 改变了数组,因此您需要在副本上执行此操作。

您可以在来自attributes.titlestring 上使用localeCompare。在引擎盖下,比较使用number,因此我们可以将结果乘以-1 以颠倒顺序。

const reviews = [...props.reviews].sort( (a, b) => 
  (order === "desc" ? -1 : 1 ) * a.attributes.title.localeCompare(b.attributes.title)
)

与 lodash 版本相比,这更难阅读,但同样简洁。

组件代码

我重写了您的 ReviewList 组件,以便它对结果进行排序,并且还包括一个用于更改排序顺序的下拉菜单。 Here is a working demo(带有非常愚蠢的虚拟数据)。

const ReviewList = (props) => {

  const [order, setOrder] = useState("asc"); // either "asc" or "desc"

  const reviews = [...props.reviews].sort(
    (a, b) =>
      (order === "desc" ? -1 : 1) *
      a.attributes.title.localeCompare(b.attributes.title)
  );

  return (
    <div className="review-list">
      <div className="sort-order">
        <label htmlFor="reviews-sort-order">Order: </label>
        <select
          id="reviews-sort-order"
          value={order}
          onChange={(e) => setOrder(e.currentTarget.value)}
          disabled={reviews.length === 0}
        >
          <option value="asc">A-Z</option>
          <option value="desc">Z-A</option>
        </select>
      </div>
      {reviews.length === 0 ? (
        <div className="no-reviews-found">No Reviews Found</div>
      ) : (
        <ul>
          {reviews.map((r) => (
            <li key={r.id}>
              <Link className="App-link" to={`/app/v1/reviews/${r.id}`}>
                {r.attributes.title}
              </Link>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

【讨论】:

  • 这太不可思议了,我认为添加该组件是最简单的。非常感谢
猜你喜欢
  • 2020-09-18
  • 1970-01-01
  • 2020-04-19
  • 2020-12-12
  • 1970-01-01
  • 2019-08-09
  • 2017-05-17
  • 1970-01-01
  • 2019-10-18
相关资源
最近更新 更多