Я использую React с Wordpress REST API. Проблема, с которой я столкнулся, заключается в том, что я не могу понять, как (правильно) использовать жизненные циклы компонента для обновления компонента Post
, когда свойство slug изменяется в корневом компоненте App
и выборке асинхронных данных.
Как я сейчас настроил, состояние компонента App
выглядит примерно так:
this.state = {
pages: this.getPages(),
slug: this.getSlug(),
homePage: this.fetchPost('home'),
};
Таким образом, свойство pages
является обещанием, и компонент App изначально отображает компонент Spinner. В конце концов асинхронный вызов получает ответ. Я выполняю фильтр для массива объектов записей, чтобы найти текущую страницу сообщений.
const thePage = this.state.pages.filter(page => {
return page.slug === slug;
});
Фильтр возвращает массив с одним объектом (эта текущая страница). Я обновляю состояние с this.setState({post: thePage[0]});
Когда я меняю маршруты изменения с помощью react-router-dom
, slug
и post
не обновляются. Ниже мой код.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './components/App/App';
// Take the React component and show it on the screen
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'));
Приложение JS:
// App.js
import React, {Component} from 'react';
import { Route, withRouter } from 'react-router-dom';
import axios from 'axios';
import './App.scss';
import {wpAPI} from '../..//api';
import {/*loadState,*/ saveState} from '../loadState/loadState';
import FrontPage from '../../pages/FrontPage';
import Header from '../Header/Header';
import Post from '../Post/Post';
import Sidebar from '../Sidebar/Sidebar';
import Footer from '../Footer/Footer';
import Spinner from '../Spinner/Spinner';
// Create a React Component
class App extends Component {
constructor(props) {
super(props);
// Bindings
this.getPages = this.getPages.bind(this);
this.getPages();
this.state = {
isHome: false,
slug: this.props.location.pathname,
fetchingPages: true,
fetchingPost: true,
};
console.log('App State: (constructor)');
console.log(this.state);
}
/**
* Fetch Data
* @return {Promise}
*/
getPages = async () => {
const response = await axios.get(wpAPI['pages']);
this.setState({
fetchingPages: false,
pages: response.data
});
saveState(this.state);
}
getPage = (slug) => {
const thePage = this.state.pages.filter(page => {
return page.slug === slug.replace('/', '');
});
this.setState({
isHome: false,
fetchingPost: false,
post: thePage[0],
slug: slug,
});
}
/**
* The component has mounted. Fetch post based on slug
*/
componentDidMount() {
console.log('App State: (componentDidMount)');
console.log(this.state);
console.log('App Props: (componentDidMount)');
console.log(this.props);
}
componentDidUpdate(prevProps, prevState) {
console.log('App State: (componentDidUpdate)');
console.log(this.state);
const {fetchingPages, fetchingPost, isHome} = this.state;
const slug = this.props.location.pathname;
if (this.state.slug !== this.props.location.pathname) {
console.log('Slugs Dont match, getting page');
this.getPage(slug);
}
if (slug === '/' && !isHome) {
console.log('Setting isHome True');
this.setState({
isHome: true,
fetchingPost: false
});
}
if (fetchingPages === false && fetchingPost === true) {
console.log('Fetching Post');
this.getPage(slug);
}
}
renderContent() {
const {post, fetchingPost} = this.state;
if (!fetchingPost) {
return (
<section id="app" className="animated fadeIn">
<Header />
<main>
<Route path="/" exact render={(props) => <FrontPage {...props} /> } />
<Route path="/:slug" exact render={(props) => <Post post={post} /> } />
</main>
<Sidebar />
<Footer />
</section>
)
}
return <Spinner message='loading data...' />;
}
render() {
return this.renderContent();
}
};
export default withRouter(App);
Post.js
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
import './Post.scss';
import Spinner from '../Spinner/Spinner';
class Post extends Component {
constructor(props) {
super(props);
this.state = {
slug: props.slug,
post: props.post,
};
}
componentDidMount() {
console.log('Post State: (componentDidUpdate)');
console.log(this.state);
}
componentDidUpdate() {
console.log('Post State: (componentDidUpdate)');
}
render() {
if ( this.state.post ) {
const {post} = this.state;
return (
<div className={`post post-${post.id} ${post.slug} animated fadeIn`}>
<header>
<h1 className="small-caps" dangerouslySetInnerHTML={{__html: post.title.rendered}}></h1>
</header>
<section id="content" dangerouslySetInnerHTML={{__html: post.content.rendered}}></section>
</div>
)
}
return <Spinner message='Fetching Post...'/>
}
}
export default withRouter(Post);