首页 文章

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

提问于
浏览
1

我正在将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);

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

显然,当我已经将所有东西都加载到商店中时,我不想再对API做任何事情,只需将其发布到商店之外 .

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

2 回答

  • 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

    感谢@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})
                })
            }
    }
    

相关问题