我尝试了一段时间来创建一个使用React & Redux的应用程序。在应用程序启动时,<App>
组件将从JSON中获取一些数据,然后调用reducer来设置接收到的数据的状态。到目前为止,这是可行的,在加载页面后不久,我就可以从JSON看到呈现的数据。
我现在要做的是使用一个<button>
从我的帖子列表中选择一个特定的帖子,使用还原器和一个动作。我尝试了几种方法,但是组件的状态保持不变,或者返回的状态是操作的类型,原因很奇怪。有人能解释我做错了什么以及如何解决吗?
actions.js
export const select = () => {
return { type: 'SELECT' }
};
export const fetchPosts = (posts) => {
return { type: 'FETCH', posts }
};
reducer.js
const reducer = (state = { data: [], selected: []}, action) => {
let posts = { data: [], selected: []};
switch (action.type) {
case 'FETCH':
Object.assign(posts.data, action.posts);
return posts;
case 'SELECT':
posts.data = [...state.data];
posts.selected = ["autumn-eu-dolor-ac-velit"];
return posts;
default:
return state;
}
};
export default reducer;
App.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { select, fetchPosts } from './actions';
// App component
class App extends Component {
constructor(props){
super(props);
this.state = { posts : this.props.posts }
}
// Fetch data from JSON file
componentDidMount() {
let _this = this;
fetch("https://jsonbin.io/b/59f721644ef213575c9f6531")
.then( response => response.json())
.then( data => {
let posts = { data: data, selected: [] };
_this.setState({ posts });
_this.props.fetchPosts(posts);
});
}
// Render
render() {
let posts = '';
if(this.state.posts && this.state.posts.data){
if (this.state.posts.selected.length){
posts = this.state.posts.data.filter(post => {if (this.state.posts.selected.includes(post.id)) return true; return false;}).map(post => {return <p key={"post_"+post.id}>{post.content}</p>;});
}
else {
posts = this.state.posts.data.map(post => {return <p key={"post_"+post.id}>{post.content}</p>;});
}
}
return (
<div>
<button onClick = {() => this.props.select()}>Select post</button>
{posts}
</div>
);
}
}
// Map state to props
const mapStateToProps = (state) =>{
return { posts: state };
};
// Connect App
export default connect(mapStateToProps, {select, fetchPosts})(App);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
据我所知,我目前拥有的代码没有设置<App/>
组件的<App/>
,因此它不会重登。但是,使用setState()
会导致一个与传递的action
相等的对象,所以我非常肯定有什么地方出了问题。
发布于 2017-10-31 04:07:07
由于您使用的是Redux,我建议您使用道具而不是组件的状态。另外,我换了你的减速机让它工作。我添加了一个default_state
(它对应于还原器中的posts
变量),并修改了案例中的代码以使其工作:
default_state = {
data: [],
selected: [],
}
const reducer = (state = default_state, action) => {
switch (action.type) {
case 'FETCH':
return default_state;
case 'SELECT':
return {
...state,
selected: ["autumn-eu-dolor-ac-velit"]
}
default:
return state;
}
};
export default reducer;
为了处理您的操作,请使用this.props.dispatch
。我建议您查找一些react + redux指南来查看工作流,然后将其应用到您的代码中。
发布于 2017-10-31 04:15:31
您似乎对redux是什么以及它与react组件之间的关系感到困惑,但是总的想法是正确的。在您的示例中,您要将json结果保存到组件的本地状态(这与redux无关),并且只在呈现方法中读取该本地状态。我将阅读整个redux教程,以详细了解这里提供的示例,特别是redux数据是如何从redux存储作为道具而不是状态传递到组件中的。完全放弃this.state和this.setState。
看一看减速器,因为您目前没有正确地做这件事,所以您正在完全重置状态。
您的SELECT操作也应该在post的某些标识符中进行,这样您就可以知道选择了哪个帖子。
<button onClick = {() => this.props.select()}>Select post</button>
这没什么用吗?它没有引用一个帖子,它怎么知道选择哪个帖子?在每个post中都有这个按钮,并将post id传递给select函数。
发布于 2017-10-31 04:29:36
当您单击select时,您的应用程序正在重新呈现,但是当发生这种情况时,它是更新的道具,而不是状态。在这里使用redux的方式,根本没有理由使用组件状态。只需将应用程序中的所有this.state
切换到this.props
即可。此外,对象分配是不必要的,您可以只使用return action.posts;
。
https://stackoverflow.com/questions/47033396
复制相似问题