State change does not cause render

I have been trying for a little while to create an application with React & Redux. On application startup, the <App> component will fetch() some data from a JSON API, then call the Redux reducer to set the state with the received data. This works so far and I see the rendered data from the JSON pretty soon after loading the page.

What I am now trying to do is use a <button> to select a specific post from my list of posts, utilizing the reducer and an action. I have tried several things, however either the state of the component remains unchanged or the returned state is the type of the action for some odd reason. Can anyone explain what I’m doing wrong and how to fix it?

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

As far as I can tell, the code I have currently does not set the state of the <App/> component, thus it will not rerender. However, using setState() resulted in an object equal to the action passed, so I’m pretty sure something went really wrong there.

58 thoughts on “State change does not cause render”

Leave a Comment