marmeladze
marmeladze

Reputation: 6564

Why redux doesn't change state?

I am building a simple React Native app with Redux.

Here is my initial state

import { createStore } from "redux";
import reducer from "../reducers";

const initialState = {
  user: {
    uuid: null,
    bio: null,
    gender: null,
    full_name: null,
    cover_photo: null,
    profile_photo: null 
  },
  followers: {
    count: 0,
    list: null
  },
};

export const store = createStore(reducer, initialState);

action

export const fetch_followers = (resp) => {
  return {
    type: FETCH_FOLLOWERS_SUCCESS,
    payload: resp
  }  
} 

reducer

import { 
  FETCH_FOLLOWERS_SUCCESS 
} from '../actions';

export default (state, action) => {
  switch(action.type){
    case FETCH_FOLLOWERS_SUCCESS:
      return {
        ...state,
        followers: {
          count: action.payload.profiles.length,
          list: action.payload.profiles
        }
      }
    default:
      return state
  }
}

api wrapper

class Client {
  constructor() {
    this.endpoints = {
        FETCH_MY_FOLLOWERS: 'https://run.mocky.io/v3/3d60da9d-1dd5-4e10-a69c-f2eefaa9a5da',
        FETCH_I_AM_FOLLOWING: 'https://run.mocky.io/v3/3d60da9d-1dd5-4e10-a69c-f2eefaa9a5da',

    }
  }

  followers() {
    return fetch(this.endpoints.FETCH_MY_FOLLOWERS).then(response => response.json());
  }

}

const client = new Client()
export default client;

my view component

import React, { Component } from 'react';
import {SafeAreaView, ScrollView} from 'react-native';
import Follower from '../components/Follower'; 
import client from '../helpers/rabonia_sdk/RaboniaClient';
import { fetch_followers } from '../actions';
import { store } from '../store';



export default class Follow extends Component {
  constructor(){
    super()
  }

  componentDidMount() {
    client.followers().then(resp => {
        if(resp.status === "OK") {
          store.dispatch(fetch_followers(resp))
        }
    });
  }

  render() {
    return (
      <SafeAreaView>
        <ScrollView>
          {store.getState().followers.list.map(follower => <Follower follower={follower} /> )}
        </ScrollView>
      </SafeAreaView>
    );
  }
}

and that one is the mock api response

{
  "status": "OK",
  "message": "Fetched",
  "profiles": [
   {"uuid": "a72ef52a-b814-4bc8-85ee-263621a6d96d", "full_name": "Michael Ballack", "profile_photo": "https://picsum.photos/200" },
   {"uuid": "a72ef52a-b814-4bc8-85ee-263621a6d96d", "full_name": "Patrice Evra", "profile_photo": "https://picsum.photos/200" },
   {"uuid": "a72ef52a-b814-4bc8-85ee-263621a6d96d", "full_name": "Dennis Bergkamp", "profile_photo": "https://picsum.photos/200" },
   {"uuid": "a72ef52a-b814-4bc8-85ee-263621a6d96d", "full_name": "Michael Owen", "profile_photo": "https://picsum.photos/200" }
  ]
}

I've the same structure for other components and they work without problem.

When I switch to local state (see below) it works, but can not determine what is problem with dispatching api payload to redux state?

export default class Follow extends Component {
  constructor(){
    super()
    this.state = {
      followers: []
    }
  }

  componentDidMount() {
    client.followers().then(resp => {
        if(resp.status === "OK") {
          this.setState({followers: resp.profiles});
          store.dispatch(fetch_followers(resp))
        }
    });
  }

  render() {
    let collection = store.getState().followers.list || this.state.followers
    return (
      <SafeAreaView>
        <ScrollView>
          {collection.map(follower => <Follower follower={follower} /> )}
        </ScrollView>
      </SafeAreaView>
    );
  }
}

Upvotes: 1

Views: 84

Answers (3)

vignesh K B
vignesh K B

Reputation: 124

In the reducer file you have to assign it with the initialState That you declared on the top

export default (state = initialState , action) => {
  switch(action.type){
    case FETCH_FOLLOWERS_SUCCESS:
      return {
        ...state,
        followers: {
          count: action.payload.profiles.length,
          list: action.payload.profiles
        }
      }
    default:
      return state;
  }
}

Upvotes: 3

Hugo Gresse
Hugo Gresse

Reputation: 17879

The Follow component is not connected to Redux, either with a HOC or a useSelector.

Documentation here

Example:

const mapStateToProps = (state) => ({
    followers: getFollowersListSelector(state),
})


export default connect(
    mapStateToProps,
    {}
)(Follow)

The selectors:

export const getFollowersSelector = state => state.followers

export const getFollowersListSelector = state => getFollowersSelector(state).list

And use it in render:

this.props.followers.map(...)

Side note: you could use a function component and React & Redux Hooks to keep the code to a minimum and make the code more readable.

Upvotes: 3

davnicwil
davnicwil

Reputation: 30957

I've the same structure for other components and they work without problem.

Without seeing the other components it's unclear what exactly you mean but your store isn't connected to your component here, that's why the component doesn't re-render when the redux state updates.

See the docs for connect() here: https://react-redux.js.org/api/connect

Upvotes: 2

Related Questions