我一直试图用React&amp; amp;创建一个应用程序终极版。在应用程序启动时,<App>
组件将fetch()
来自JSON API的一些数据,然后调用Redux reducer以使用接收的数据设置状态。这个工作到目前为止,我在加载页面后很快就会看到来自JSON的渲染数据。
我现在要做的是使用<button>
从我的帖子列表中选择特定帖子,使用reducer和一个动作。我已经尝试过几样东西,但是组件的状态保持不变,或者返回的状态是动作的类型,原因有些奇怪。任何人都可以解释我做错了什么以及如何解决它?
export const select = () => {
return { type: 'SELECT' }
};
export const fetchPosts = (posts) => {
return { type: 'FETCH', posts }
};
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;
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);
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'));
据我所知,我目前的代码没有设置state
组件的<App/>
,因此它不会重新呈现。但是,使用setState()
导致了一个等于action
的对象,所以我很确定那里出了问题。
答案 0 :(得分:2)
由于你正在使用Redux,我建议你使用道具而不是组件的状态。另外,我更换了减速机以使其正常工作。我添加了default_state
(对应于reducer中的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指南以查看工作流程,然后将其应用到您的代码中。
答案 1 :(得分:2)
你似乎对redux是什么以及它与反应成分的关系感到困惑,但总体思路是正确的。在您的示例中,您将json结果保存到组件的本地状态,该状态与redux无关,并且仅从您的本地状态读取渲染方法。我将阅读整个redux教程,以查看详细提供的示例,特别是redux数据如何从redux存储传递到组件中,如 props 而不是 state 。完全删除this.state和this.setState。
同时查看reducers,因为您此刻没有正确执行此操作,您正在完全重置状态。
您的SELECT操作还应该包含帖子的一些标识符,以便您可以知道选择了哪个帖子。
<button onClick = {() => this.props.select()}>Select post</button>
这什么都不做?它没有引用帖子,它如何知道选择哪个帖子?在每个帖子中都有这个按钮,并将post id传递给select函数。
答案 2 :(得分:1)
当您单击选择时,您的应用程序将重新呈现,但是当发生更新的道具时,而不是状态。你在这里使用redux的方式,没有理由使用组件状态。只需将应用中的所有this.state
切换为this.props
即可。此外,对象分配是不必要的,您只需return action.posts;