Получение объекта post и slug для правильного обновления в React - PullRequest
0 голосов
/ 13 января 2019

Я использую 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);

1 Ответ

0 голосов
/ 13 января 2019

В вашем коде нет ничего, что говорило бы о том, что когда ваше приложение получит новый реквизит от withRouter HOC, тогда обновите state.slug.

Вы можете добавить:

this.setState({
    slug: this.getSlug();
});

для вашей componentDidUpdate() функции, однако я не уверен, зачем вам это нужно в качестве состояния, когда оно все равно доступно как опора в this.props.location.pathname, которое передается вашему компоненту FrontPage, и его можно так же легко передать до компонента «Сообщения» таким же образом.

...