1
votes

I have a simple testing code to learn redux / react and async API calls with thunk Problem Im having is that I call dispatch in component, which makes a call to API and gets a valid response.

I console log action.payload inside reducer and I see its a valid response. It should update state.events in my code.

In my App component I use mapStateToProps and send events : state.events

As I understand when state gets update It should send new props to my Component, but when I click button in my component to log the props it gets, events is still an empty array ? What is wrong here ?

Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import './index.css';
import App from './components/App';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const initialState = {
    events: [],
    isViewingEvent : false,
    eventIndex : 0,
    eventProducts : []
}

//STORE
function reducer(state = initialState, action) {
  switch(action.type) {
    case "GETEVENTS":
        {        
          state.events = action.payload;
          console.log(action.payload)
        };

    default:
      return state;
  }
}

const store = createStore(
  reducer,
  applyMiddleware(thunk)
  );


ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

App.js

import { Component } from 'react';
import { connect } from 'react-redux'


class App extends Component {
  
  handleClick () {
    console.log(this.props)    
    this.props.getEvents();
    
  }

  render()  {
    console.log(this.props)
    return(
      <div>
        <header>
          <button onClick={()=> this.handleClick()}>TEST</button>
          <p>{}</p>
        </header>
      </div>
    )
  }
}

const getEvents = () => async (dispatch, getState) => {
    
  const response = await fetch("API URL", {
    method: 'get',
    headers: {'Content-Type':'application/json','Accept': 'application/json'}
    })
    .then(function(response) {
    
        return response.json();         
    })

    dispatch({ type: 'GETEVENTS', payload: response})
}


const mapStateToProps = (state) => {
  console.log(state);
  return {
    events: state.events
  }
}

const mapDispatchToProps = (dispatch) => {  
  return {
    getEvents: () => dispatch(getEvents())
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

Console output when I click button. I see valid response from API and this should update my state. Why are component props showing still events as empty array ?

Picture from console console log

2

2 Answers

2
votes

I can see in your reducer is that you haven't return state.

//STORE
function reducer(state = initialState, action) {
  switch(action.type) {
    case "GETEVENTS":
        {        
          //don't need to do in this way it mutate you state.
          //state.events = action.payload;
          console.log(action.payload)
          return  {...state, events: action.payload}
        };

    default:
      return state;
  }
}
0
votes

Your reducer is not returning a new state object, but just modifying the existing state. Since redux decides to rerender on the basis of lastState !== currentState, this is now doing lastState !== lastState and will never rerender.

In modern Redux, Redux Toolkit's createSlice does this "for you" in a transparent way, but you are using a way outdated style of redux. You are probably following an outdated tutorial to learn redux and I highly recommend to learn modern redux from the official Redux tutorials

If for whatever reason you are stuck with writing vanilla redux, read up on Immutable update Patterns