Unable to handle state 'loading' properly in react with redux

Ratnabh kumar rai :

Hey guys just moved to redux so in react what i was doing was in componentDidMount(), i was calling api and soon as i received the data i was setting loading to false (initially loading was true) to get rid of the 'react spinner',

but after using redux now in componentDidMount() i am calling my action creater which is in another and there i am receving my data so how do i manage 'loading' here ? can i somehow pass something from action creater to my component that triggers state and set loading to false ? or is there any other to do it ? How do you all manage it ?

here is my code

Home.js

class home extends Component {
  UNSAFE_componentWillMount() {
    this.props.verifyToken();
  }

  componentDidMount() {
    this.props.categoryAction();

  }
  constructor(props) {
    super(props);
    this.state = {
      categoriesWithTheirImages: [],
      displayToggle: false,
      loading: false,
    };
  }


  renderCategory = () => {

    return this.props.allCategories.map((item) => {
      return (
        <div
          className="category_div"
          key={item._id}
          onClick={() => this.setState({ displayToggle: true })}
        >
          <img
            src={item.image}
            alt="miss-mistake"
            className="category_image_home"
          />
          <span className="category_heading_home">{item.categoryName}</span>
        </div>
      );
    });

  };

  render() {

    if (this.state.loading) {
      return (
        <div className="sweet-loading-main">
          <FadeLoader
            css={override}
            sizeUnit={"px"}
            size={50}
            color={"#ff9d72"}
            loading={this.state.loading}
          />
        </div>
      );
    } else {
      console.log(this.props.allCategories);
      return (
        <React.Fragment>
          {/* <Fade left> */}
          <Header />
          <div className="main_content_homepage">
            <p className="category_select">Please select a category</p>
            <div className="category_list">{this.renderCategory()}</div>
          </div>
          {this.renderStoryActionDialog()}
          {/* </Fade> */}
        </React.Fragment>
      );
    }
  }
}


const mapStateToProps = (state) => {
  console.log(state);
  const images = [family, ring, beer, feedback, academic];
  let categoriesWithImages = state.getCategoryReducer.map((item, index) => {
    item.image = images[index];
    return item;
  });
  console.log(categoriesWithImages);
  return { allCategories: categoriesWithImages };
};
export default connect(mapStateToProps, { verifyToken, categoryAction })(home);

and my action.js file

import { CATEGORY } from "../actionTypes";
export const categoryAction = ()=> {
  return dispatch => {
    fetch("http://localhost:3000/api/get_categories", {
      method: "GET",
    }).then(res=>res.json())
      .then(response => {
          console.log(response)
        dispatch({ type: CATEGORY, payload: response });
      })
      .catch(err => console.log("Eror in adding", err));
  };
};

reducer file

import { USER, CATEGORY} from "../actionTypes";
const getCategoryReducer = (state = [], action) => {

  switch (action.type) {
    case CATEGORY:
      return action.payload;
    default:
      return state;
  }

};

export default getCategoryReducer;
Sid :

You should handle the loading state in your reducer file. At the moment, it's defined in your Component file. For e.g when you dispatch the action, it should update your loading state too. I would do something like this in reducer.

import { USER, FETCH_CATEGORY, FETCH_CATEGORY_SUCCESS, FETCH_CATEGORY_FAIL} from "../actionTypes";
const INITIAL_STATE = {
    loading: false,
    err: false,
    data: []
}
const getCategoryReducer = (state = INITIAL_STATE, action) => {

  switch (action.type) {
    case FETCH_CATEGORY:
       return Object.assign({}, state, {
            loading: true,
            data: [],
        })

      case FETCH_CATEGORY_SUCCESS
          return Object.assign({}, state, {
            loading: false,
            data: action.payload,
        })

       case FETCH_CATEGORY_FAIL
          return Object.assign({}, state, {
            loading: false,
            data: action.payload,
            err: true
        })

    default:
      return state;
  }

};

export default getCategoryReducer;

and your action file would look something like this

import { FETCH_CATEGORY, FETCH_CATEGORY_SUCCESS, FETCH_CATEGORY_FAIL } from "../actionTypes";
export const categoryAction = ()=> {
  //setting loading to true
  return dispatch => {
    dispatch({ type: FETCH_CATEGORY });
    fetch("http://localhost:3000/api/get_categories", {
      method: "GET",
    }).then(res=>res.json())
      .then(response => {
         //setting loading to false
        dispatch({ type: FETCH_CATEGORY_SUCCESS, payload: response });
      })
      .catch(err => console.log("Eror in adding", err);  dispatch({ type: FETCH_CATEGORY_FAIL, payload: err }););
  };
};

You can then read the loading props in your Home.js

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=405781&siteId=1