React Redux& Wordpress API - 如何从Redux商店加载单个帖子?

时间:2018-04-06 20:55:03

标签: reactjs redux wordpress-rest-api

我正在将Wordpress API与React和Redux结合使用。我设法通过API从Wordpress博客(从另一个URL)获得了几个帖子。一切都很精彩,我可以跨域发布帖子并将它们加载到Redux商店,在页面上呈现它们等。

但有一点我无法理解:对于一页上的单个帖子,我如何才能从商店访问和呈现一个帖子?

我认为我非常接近,当我直接发出行动时,我已经收到了帖子。

但是现在对于单页,我已经在商店中发帖了。我连接到商店,想要通过URL的slug获得一个帖子。

我的想法如下:

import { withRouter } from 'react-router-dom';
import { connect, mapStateToProps } from 'react-redux';    

@connect((store) => {
    return {
        posts: store.posts, 
        postsFetched: store.posts.fetched,
        users: store.users.users,
        usersFetched: store.users.fetched
    };
})

class SinglePost extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            title: 'Some test title',
            singlePost: '',
            pathname: ''
        }
    }


    componentWillMount()  {
        //Get the pathname
        var {pathname} = this.props.location;
        //remove the / in front of pathname and put pathname into parantheses
        if(pathname.charAt(0) === "/")
        var pathname = pathname.slice(1);
        console.log('pathname is:', pathname); 
        this.setState({
            pathname: pathname
        }); 

        for(var i = 0; i < this.props.posts.posts.length; i++) {
            if(this.props.posts.posts[i].slug == this.state.pathname){
                this.setState((prevState, props) => ({
                    singlePost: this.props.posts.posts[i],
                    title: this.props.posts.posts[i].title.rendered
                }));
                const singlePost = this.props.posts.posts[i];
                console.log('singlePost was fired');
            } else {
                console.log('singlePost was not fired');
            }
        }     
    }

    render() {   
        return (
            <div className="container">
                        <h2 className="text-center">{ this.state.singlePost.title }</h2>
            </div>
        );        
    }
}

export default connect(mapStateToProps) (SinglePost);

我得到btw的路径名。我为for循环尝试了其他几个地方(shouldComponentUpdate,componentWillReceiveProps等),但是组件没有渲染,或者我得到了singlePost.title但是在无限循环中。

显然,当我已经将所有内容加载到商店中时,我不想再对API做任何事情,只需将其发布到商店外即可。

任何想法,我可以研究的事情,建议?

2 个答案:

答案 0 :(得分:1)

尝试通过slug键入你传入的帖子数据,这样你的帖子数据的形状就是这样。

posts: {
 slug_1: { ... },
 slug_2: { ... }
};

这允许您在需要时直接通过slug抓取它,而不必遍历潜在的大型对象数组。

state.posts[slug]

你可以在你的reducer中重塑你传入的帖子数据:

return data.map(post => ({[post.slug]: post}))

我个人建议在你的functions.php中编写一个小的自定义函数来处理一个slug查询并返回那个帖子,从而消除了对这种客户端工作的需要。

这看起来像是:

function get_post_from_slug($data) {
  $slug = $data['slug'];
  $post = get_page_by_path($slug, OBJECT, array('post'));
  return new WP_REST_Response($post, 200);
}

add_action( 'rest_api_init', function() {
  $version = '/v1';
  $namespace = 'my-awesome-api' . $version;

  register_rest_route( $namespace, '/post' , array(
    'methods' => 'GET',
    'callback' => 'get_post_from_slug',
  ));
});

// Endpoint
../wp-json/my-awesome-api/v1/post?slug=slug_1

希望这有帮助!

答案 1 :(得分:1)

感谢@Anthony的回答,我得到了一个更好的基本想法,而不是从API获取一个帖子(而不是从数组中的所有帖子中过滤出来)

以下是我的代码的外观:

import { withRouter } from 'react-router-dom';
import { connect, mapStateToProps } from 'react-redux';
import { getPostByURL } from 'redux/actions/postsActions.js';

@connect((store) => {
    return {
        singlePost: store.singlePost,
        singlePostFetched: store.singlePost.fetched,
        users: store.users.users,
        usersFetched: store.users.fetched
    };
})

class SinglePost extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            pathname: ''
        }
    }


    componentWillMount() {        
        //Get the pathname
        var {pathname} = this.props.location;

        //remove the / in front of pathname and put pathname into parantheses
        if(pathname.charAt(0) === "/")
        var pathname = pathname.slice(1);

        this.setState({
            pathname: pathname
        });     

        this.props.dispatch(getPostByURL(pathname));  
    }   


    render() {            
        const { users, singlePost } = this.props;

        return (
            <div className="container">   
               {singlePost.singlePost.map(post => {
                        return(
                            <div>
                                 <h1>{post.title.rendered}</h1>
                            </div>                                        
                        );
                })}
            </div>
        );        
    }
}

export default connect() (SinglePost);

我的postsActions.js的一部分:

export function getPostByURL(pathname) {
    return function(dispatch){
        console.log(pathname);
        axios.get(`http://example.com/wp-json/wp/v2/posts/?filter[name]=${pathname}&_embed`)
            .then((response) => {       
                dispatch({type: 'FETCH_POST_BY_URL_FULFILLED', payload: response.data});          
            })
            .catch((err) => {
                dispatch({type: 'FETCH_POST_BY_URL_REJECTED', payload: err})
            })
        }
}