状态更改不会导致渲染

时间:2017-10-31 10:43:41

标签: javascript reactjs ecmascript-6 redux react-redux

我一直试图用React&amp; amp;创建一个应用程序终极版。在应用程序启动时,<App>组件将fetch()来自JSON API的一些数据,然后调用Redux reducer以使用接收的数据设置状态。这个工作到目前为止,我在加载页面后很快就会看到来自JSON的渲染数据。

我现在要做的是使用<button>从我的帖子列表中选择特定帖子,使用reducer和一个动作。我已经尝试过几样东西,但是组件的状态保持不变,或者返回的状态是动作的类型,原因有些奇怪。任何人都可以解释我做错了什么以及如何解决它?

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'));

据我所知,我目前的代码没有设置state组件的<App/>,因此它不会重新呈现。但是,使用setState()导致了一个等于action的对象,所以我很确定那里出了问题。

3 个答案:

答案 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;