如何使用 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);
我是 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);