Компонент React не будет повторно отображаться при смене реквизита - PullRequest
0 голосов
/ 24 декабря 2018

Это компонент 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.Из того, что было зарегистрировано внутри mapStateToProps() выше state.filter.sortBy, изменяется правильно.

Как мне заставить BookList повторно выполнить рендеринг при изменении значения sortBy?Полное репо на https://github.com/ElAnonimo/booklist Пока я пробовал 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 компоненту BookList.Что привело к отсутствию смены реквизита для Redux.

Вот так я и получил его, чтобы вернуть измененную копию исходного массива.

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;
      }
    });
};

Кредит переходит к Райану С.

ОБНОВЛЕНИЕ 2. Еще одна заслуга Райана С. Спасибо, что поделились мудростью.

Вот его предлагаемые изменения.

booksReducer.До этого не было случаев SORT_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

const mapStateToProps = (state) => ({
    books: state.books.books
});

Эти изменения фактически исключают необходимость выбора впроект.

1 Ответ

0 голосов
/ 24 декабря 2018

Я подозреваю, что ваш метод sortBooks сортирует массив на месте, так что всегда возвращается одна и та же ссылка на массив books (даже если порядок элементов в нем может быть изменен).Это приводит к тому, что response-redux считает, что свойства, возвращаемые mapStateToProps, не изменились (response-redux только делает поверхностное сравнение).Если вы измените sortBooks, чтобы сначала дублировать массив, а затем отсортировать его и вернуть новый массив, а не изменять существующий массив, он должен работать.

ОБНОВЛЕНИЕ После просмотра вашего разрешения яЯ думаю, что было бы лучше обработать эту сортировку в вашем редукторе, так как массив книг находится в состоянииТаким образом, вы можете контролировать выполнение сортировки только в ответ на действие, которое меняет сортировку.Теперь так и будет, в конечном итоге вы будете перерисовывать список книг при каждом изменении состояния (даже если сортировка не изменилась), поскольку mapStateToProps ВСЕГДА вернет другой массив книг.

...