如何使用 React 和 Redux 显示已加载的帖子

How to display loaded posts with React and Redux

我是 React 和 Redux 的新手,我正在尝试从 WordPress REST API 加载 posts,并在我的 React 应用程序中显示它们。

我以此为例:https://github.com/jackreichert/a-wp-react-redux-theme

我获得 post 的操作如下所示:

import axios from 'axios';
export const FETCH_POSTS = 'FETCH_POSTS';

export function fetchPosts(post_type = 'posts') {
    return function (dispatch) {
        axios.get(`http://localhost:8080/wp-json/wp/v2/${post_type}`)
            .then(response => {
                dispatch({
                    type: FETCH_POSTS,
                    payload: response.data
                });
            });
    }
}

它传递给reducer,看起来像这样:

import { FETCH_POSTS } from '../actions';

export default (state = [], action) => {
    switch (action.type) {
        case FETCH_POSTS:
            return action.payload;
        default :
            state = '';
        break;
    }
    return state;
}

并且(虽然它只是一个reducer)我正在组合它,因为有更多的reducer可以跟随(就像在示例中一样),然后我正在存储它。也与示例几乎相同。

我正在将所有内容加载到我的 Home.jsx 文件中,现在看起来像这样:

import React, { Component } from 'react';
import {connect} from 'react-redux';
import { Link } from 'react-router-dom';

import Header from '../Header';
import {fetchPosts} from '../../actions/';

class Home extends Component{
    componentDidMount(){
        document.title = 'Test';
    }

    componentWillMount() {
        this.getPosts(this.props, true);
    }

    componentWillReceiveProps(nextProps) {
        this.getPosts(nextProps);
    }

    getPosts(props, willMount = false) {
        if (willMount) {
            this.props.fetchPosts();
        }
    }
    render() {
        return(
            <div>
                <Header/>
                <main>
                  <h1>Home</h1>
                </main>
            </div>
        )
    }
}

function mapStateToProps({posts}) {
    return {posts};
}

export default connect(mapStateToProps, {fetchPosts})(Home);

我认为我上面的代码是正确的。 Redux 也可以 'find' 我的 posts, 在我的控制台登录:

action FETCH_POSTS @ 11:11:56.393
    prev state Object {posts: ""}
    action     Object {type: "FETCH_POSTS", payload: Array(2)}
    next state Object {posts: Array(2)} 

现在我想知道:如何在我的 Home.jsx 文件中简单地显示 Redux 加载的 posts。 之后:如何配置路由和数据,以转到单个 post(但稍后会出现,现在我只想知道一种简单但正确的方法来显示 posts)

如果您正确实施了 combineReducers,那么当 mapStateToPosts 发生变化时,应该使用一组帖子调用它。

import posts from './posts_reducer';

combineReducers({ posts });

要在 Home 组件中呈现帖子,您需要修改呈现函数,请参阅下面的原始实现:

render() {
    let postsElements = this.props.posts.map(p => {
        return <div>p.title</div>
    });
    return(
        <div>
            <Header/>
            <main>
              <h1>Home</h1>
            </main>
            <div>
                {postsElements}
            </div>
        </div>
    )
}

您需要使用 this.props.posts 来访问您的帖子,因为 react-redux 使用 mapStateToProps 函数将属性从状态映射到组件的 props 对象,该函数作为调用 connect 函数时的第一个参数。

要改进这一点,您可以实现博客组件并用它替换 div

此外,请查看您在此文件中提供的示例中如何实现它 https://github.com/jackreichert/a-wp-react-redux-theme/blob/master/src/components/main.js 呈现帖子。

我不知道你的 Post 对象的结构。但应该是这样的。

renderPosts() {
  return _.map(this.props.posts, post => {
    return (
      <li className="list-group-item" key={post.id}>
          {post.title}
      </li>
    );
  });
}

然后在你的 render 方法中就这样调用它。

  render() {
    return (
      <div>
        <h3>Posts</h3>
        <ul className="list-group">
          {this.renderPosts()}
        </ul>
      </div>
    );
  }

另请注意,我在这里使用 lodash 库中的 map 助手。所以你需要在你的组件中有以下导入语句。

import _ from 'lodash';

希望这对您有所帮助。编码愉快!

import React, { Component } from 'react';
import { connect } from 'react-redux'; // glue between react and redux
import Parser from 'html-react-parser';
import { LinkContainer } from 'react-router-bootstrap';
import { ListGroup, ListGroupItem, Image } from 'react-bootstrap';

class BlogPosts extends Component {
  render() {
    if (!this.props.posts) {
      return (<div></div>);
    }
    return (
     <div className="blog-items" >
        <ListGroup>
          {this.renderBlogPosts()}
        </ListGroup>
     </div>
    )
  };
  renderBlogPosts() {
    if (this.props.posts.posts) { //v1
      const posts = this.props.posts.posts; // DRY
      return posts.map((post, index) => {
        const excerptText = JSON.stringify(post.excerpt);
        const excerpt = excerptText.substring(1, excerptText.length-3);
        return (
          <LinkContainer className="blog-posts-link" key={post.ID} to={ "/blog/post/" + post.ID + '/'}>
            { this.getHtml(
              post.ID,
              (post.featured_image) ? post.featured_image : '',
              post.title,
              excerpt 
            )}
          </LinkContainer>
        );
      });
    };
    const posts = this.props.posts; // DRY
    return posts.map((post, index) => { // v2
      return (
        <div key={post.id}>
          {this.getHtml(
            post.id, 
            (post._embedded['wp:featuredmedia']) 
              ? post._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url : '',
            post.title.rendered,
            post.excerpt.rendered
          )}
        </div>
      );
    });
  };
  getHtml(id, imageSrc, title, excerpt) {
    return (
      <ListGroupItem className="blog-posts-list-item">
        {this.getImage(imageSrc, title)}
        <h2 className="blog-posts-title">{ Parser(title) }</h2>
        <div className="blog-posts-excerpt">{Parser(excerpt)}</div>
      </ListGroupItem>
    );   
  };
  getImage(imageSrc, title) {
    return (imageSrc === "") 
      ? (<div></div>) 
      : (<div className="blog-posts-image-div">
          <Image className="blog-posts-image" src={imageSrc} alt={title} />
        </div>
      );
  };
};

const mapStateToProps = (state) => ({ posts: state.posts });
export default connect(mapStateToProps) (BlogPosts);