Это компонент 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
});
Эти изменения фактически исключают необходимость выбора впроект.