获取发布对象和插件以在React中正确更新

时间:2019-01-12 21:14:19

标签: reactjs react-router state wordpress-rest-api

我正在将React与Wordpress REST API一起使用。我遇到的问题是,当根Post组件上的Slug属性更改并获取异步数据时,我似乎无法全神贯注于如何(正确)使用组件生命周期来更新App组件。

我目前设置的方式,App组件状态如下所示:

this.state = {
   pages: this.getPages(),
   slug: this.getSlug(),
   homePage: this.fetchPost('home'),
};

因此,pages属性是一个promise,App组件最初将呈现Spinner组件。最终,异步调用收到响应。我对发布对象数组执行过滤,以查找当前页面发布。

const thePage = this.state.pages.filter(page => {
                return page.slug === slug;
            });

过滤器返回一个带有一个对象的数组(当前页面)。我用this.setState({post: thePage[0]});

更新状态

当我使用react-router-dom更改更改路由时,slugpost没有更新。下面是我的代码。

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

App 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 :(得分:0)

代码中没有什么可以说的是,当您的应用从HttpClient httpClient = new HttpClient(); string html = await httpClient.GetStringAsync("http://www.wordreference.com/definicion/mundo"); HOC接收新道具时,然后更新withRouter

您可以添加:

state.slug

到您的this.setState({ slug: this.getSlug(); }); 函数,但是我不确定为什么当它在componentDidUpdate()中仍然可以作为道具被传递给您的FrontPage组件时,为什么需要它作为状态同样可以轻松地传递到您的Posts组件。