Я практикую реагирование и редукцию, и я создаю простое приложение, в котором у меня есть боковая панель, показывающая список категорий, который виден на каждом маршруте, и основная область, в которой изначально отображаются все книги, которые у меня есть, и при нажатии нассылка категории на боковой панели основной области, загружающей другой компонент со всеми книгами, относящимися к этой категории.
Вот мои настройки маршрутов в файле App.js
...
class App extends Component {
async componentDidMount() {
try {
await this.props.asyncLoadBooks();
await this.props.asyncLoadCategories();
} catch (error) {
console.log(error);
}
}
render() {
return (
<>
<Header />
<div className="global-wrapper">
<div className="container">
<aside className="side-bar">
<Categories />
</aside>
<main className="main-content">
<Switch>
<Route exact path="/" component={Books} />
<Route
exact
path="/category/:id"
component={Category}
/>
<Route component={NotFound} />
</Switch>
</main>
</div>
</div>
</>
);
}
}
InApp.js
, как вы можете видеть, я загружаю данные через локальный файл JSON с axios в Actions
файлах booksActions
и categoriesAction
, это довольно просто.
И вотКомпонент категорий ...
class Categories extends Component {
render() {
const { categories } = this.props;
let categoriesList;
if (categories && categories.length !== 0) {
categoriesList = categories.map(category => (
<li key={category.id}>
<Link to={`/category/${category.id}`}>{category.name}</Link>
</li>
));
} else {
categoriesList = <Loading />;
}
return (
<div>
<h2>Categories</h2>
<ul>{categoriesList}</ul>
</div>
);
}
}
const mapState = state => ({
categories: state.categories.categories
});
export default connect(mapState)(Categories);
И я запускаю еще одно действие в ComponentDidMount()
одного компонента категории, чтобы получить все книги, связанные с этим компонентом, и отобразить их ...
class Category extends Component {
componentDidMount() {
this.props.getCategoryBooks(this.props.match.params.id);
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.id !== this.props.match.params.id) {
this.props.getCategoryBooks(this.props.match.params.id);
}
}
render() {
const { categoryBooks } = this.props;
return (
<div>
{/* <h1>{this.props.match.params.id}</h1> */}
{categoryBooks &&
categoryBooks.map(book => {
return <div key={book.id}>{book.title}</div>;
})}
</div>
);
}
}
const mapState = state => ({
categories: state.categories.categories,
categoryBooks: state.books.categoryBooks
});
const mapActions = {
getCategoryBooks
};
export default connect(
mapState,
mapActions
)(Category);
Теперь все работает в первый раз, однако, когда я нажимаю на другую категорию, компонент <Category />
не обновляется, потому что я отправляю действие в componentDidMount()
, таким образом, tКомпонент уже смонтирован в первый раз, поэтому он не отправляет действие снова после того, как я нажму на другую категорию, теперь, каков наилучший способ справиться с этим?
Второй вопрос, где я нахожусь наКатегория route http://localhost:3000/category/9967c77a-1da5-4d69-b6a9-014ca20abd61
и я пытаюсь обновить страницу, список категорий загружается нормально на боковой панели, но отдельный компонент отображается пустым, и когда я смотрю на redux-devtools, я обнаруживаю, что действие GET_CATEGORY_BOOKS
запускается до того, какLOAD_BOOKS
и LOAD_CATEGORIES
в файле App.js
, потому что дочерний метод componentDidMount()
вызывается перед его родительским эквивалентным методом.Как это тоже решить?
Надеюсь, вы, ребята, можете мне помочь в этом.
Редактировать
Как заметил @@ NguyễnThanhTú, в компонентеDidupate была опечатка, теперь онаработает при нажатии на другую категорию.Это оставляет нас со второй проблемой при перезагрузке страницы в маршрут категории, и данные не отображаются из-за запуска App.js componentDidMount после его дочерних компонентов.
Edit
Вотрепо на Github для этого проекта ... https://github.com/Shaker-Hamdi/books-app