React组件不会在道具变更时重新呈现

时间:2018-12-24 14:19:08

标签: reactjs redux react-redux

这是BookList属性更改中要重新呈现的filter.sortBy组件。

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getBooks } from '../actions/bookActions';
import Spinner from './Spinner';
import BookItem from './BookItem';
import sortBooks from '../selectors/books';

class BookList extends Component {
  componentDidMount() {
    this.props.getBooks();
  }

  render() {
    const { books, loading } = this.props;

    let booksContent;

    if (!books || loading) {
      booksContent = <Spinner />;
    } else {
      if (books.length > 0) {
        booksContent = books.map(book => <BookItem book={book} key={book._id} />);
      } else {
        booksContent = <h4>No books found</h4>;
      }
    }

    return (
      <div className='feed'>
                <div className='container'>
                    <div className='row'>
                        <div className='col-md-12'>
                            {booksContent}
                        </div>
                    </div>
                </div>
            </div>
    );
  }
}

BookList.propTypes = {
  books: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
  getBooks: PropTypes.func.isRequired
};

const mapStateToProps = (state) => {
  const books = sortBooks(state.books.books, state.filter.sortBy);

  return {
    books: books
  }
};

export default connect(mapStateToProps, { getBooks })(BookList);

还有另一个组件可以更改state.filter.sortBy的值。根据{{​​1}}上方mapStateToProps()内部记录的内容,正确进行了更改。

更改state.filter.sortBy的值后,如何重新渲染BookList? 完整的仓库位于https://github.com/ElAnonimo/booklist 到目前为止,我已经在sortBy中尝试过constructor()componentWillReceiveProps()

更新。

这是我的BookList选择器的样子

sortBooks

正如在接受的答案中提到的那样,选择器将内部修改后的原始export default (books, sortBy) => { return books .sort((a, b) => { if (sortBy === 'title') { return a.title < b.title ? -1 : 1; } else if (sortBy === 'releasedAt') { return a.releasedAt < b.releasedAt ? -1 : 1; } }); }; 数组返回给books组件。导致Redux的道具没有变化。

这就是我如何返回原始数组的修改后的副本。

BookList

这归功于Ryan C。

更新2。 还要感谢RyanC。感谢您分享智慧。

这是他建议的修改方法。

export default (books, sortBy) => { return [...books] .sort((a, b) => { if (sortBy === 'title') { return a.title < b.title ? -1 : 1; } else if (sortBy === 'releasedAt') { return a.releasedAt < b.releasedAt ? -1 : 1; } }); }; 。在缺少booksReducerSORT_BY_TITLE案件之前。

SORT_BY_RELEASED_AT

import { GET_BOOKS, BOOKS_LOADING, DELETE_BOOK, SORT_BY_TITLE, SORT_BY_RELEASED_AT } from '../actions/types'; const initialState = { books: [] }; export default function(state = initialState, action) { switch(action.type) { case BOOKS_LOADING: return { ...state, loading: true }; case GET_BOOKS: return { ...state, books: action.payload, loading: false }; case DELETE_BOOK: return { books: [...state.books.filter(book => book._id !== action.payload.id)] }; case SORT_BY_TITLE: return { ...state, books: [...state.books.sort((a, b) => a.title < b.title ? -1 : 1 )] }; case SORT_BY_RELEASED_AT: return { ...state, books: [...state.books.sort((a, b) => a.releasedAt < b.releasedAt ? -1 : 1 )] }; default: return state; } }

的修改
BookList

这些更改实际上消除了项目中对选择器的需求。

1 个答案:

答案 0 :(得分:2)

我怀疑您的sortBooks方法正在对数组进行排序,从而始终返回相同的books数组引用(即使其中的元素顺序可能已更改)。这导致react-redux认为mapStateToProps返回的属性没有更改(react-redux仅做一个浅表比较)。如果您将sortBooks更改为首先复制该数组,然后对其进行排序并返回新数组,而不是对现有数组进行突变,那么它将起作用。

更新 看到您的解决方案后,我认为最好在化简器中进行这种排序,因为books数组处于状态。这样,您只能控制响应于更改排序的操作进行排序。现在,由于mapStateToProps 总是返回一个不同的books数组,因此每次状态更改(即使排序没有改变)时,您最终都将重新呈现书单。