Ad

How To Update Component On State Change In Redux

- 1 answer

I am trying to update component on state change in redux. I have a list of images, when user deletes the image the component should update after deleting the targeted image.

I have tried using componentWillReceiveProps and componentDidUpdate life cycle method, but none is working here. Can someone please suggest me what I am doing wrong here?

what I have done so far

action

import { DELETE_GALLERY_SUCCESS, DELETE_GALLERY_FAIL} from "./types";

export const deleteGalleryImage = (id) => (dispatch, getState) => {
    axios    
        .delete(`${baseURL}/api/aws/gallery/${id}/delete/`, tokenConfig(getState))

        .then(res => {
            dispatch({
                type: DELETE_GALLERY_SUCCESS,
                payload: res.data
            });


        })
        .catch(err => {
            dispatch(returnErrors(err.response.data, err.response.status));
            dispatch({
                type: DELETE_GALLERY_FAIL
            });
        });
}; 

types.js

export const DELETE_GALLERY_SUCCESS = "DELETE_GALLERY_SUCCESS"
export const DELETE_GALLERY_FAIL = "DELETE_GALLERY_FAIL"

Reducer

import {DELETE_GALLERY_SUCCESS, DELETE_GALLERY_FAIL} from "../actions/types";

const initialState = {
    paginations: true,
    isLoading: false,
    gallery: [],

};


export default function (state = initialState, action) {
    switch (action.type) {
        case DELETE_GALLERY_SUCCESS:
           return {
                ...state,
                isLoading: false,
                gallery: state.gallery.filter(gallery => gallery.id !== action.payload)
            };

        case DELETE_GALLERY_FAIL:
            return {
                ...state,
                isLoading: false
            };

        default:
            return state;
    }
}

Here is my component

import { getAllGalleryImages, deleteGalleryImage } from '../settings/../../actions/gallery';


class DeleteGalleryImage extends Component {

    componentDidMount() {
        this.props.getAllGalleryImages();
    }

    componentWillReceiveProps(nextProps) {
        if (this.props.images !== nextProps.images) {

            // This is not working.
            // what life cycle method should I use for this scenario?

            //this.props.getAllGalleryImages()

        }
    }
    handleDelete = (id) => {
        this.props.deleteGalleryImage(id)
    }    
    render() {
        return (

            <Row>
                <Col xs={24} sm={22} offset={1}>
                    <h1 className='sub-page-heading'><span className='common_dlt'>Delete</span> Gallery Image</h1>
                    <div className='masonry'>

                        {this.props.images && this.props.images.results && this.props.images.results.map(result =>


                            <div className='masonry-item' key={result.id}>
                                <img src={result.gallery_img_url} className='dlt_blg_img' alt='img' id={result.id} />
                                <span className='gallery_delete_zone' onClick={() => this.handleDelete(result.id)}><Icon type="delete" /></span>
                            </div>

                        )}

                    </div>
                </Col>
            </Row>
        )
    }
}   
const mapStateToProps = state => ({
    images: state.gallery

});
export default connect(
    mapStateToProps,
    { getAllGalleryImages, deleteGalleryImage }
)(DeleteGalleryImage);

Store

import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";

const initialState = {};

const middleware = [thunk];

const store = createStore(
  rootReducer,
  initialState,
  composeWithDevTools(applyMiddleware(...middleware))
);

export default store;

rootReducer

import { combineReducers } from "redux";
import gallery from './gallery';

    export default combineReducers({
      gallery,

    });
Ad

Answer

In this case no need to use componentWillReceiveProps, If you can change the store succcesfully the component will be rendered automatically since it is connected to the store.

Another thing I noticed is in your deleteGalleryImage action, I think you need to send id input parameter as payload, because we cannot assume if res.data will be id.

dispatch({
    type: DELETE_GALLERY_SUCCESS,
    payload: id
})

Edit: based on the info I got from comments, I understood your initial state

const initialState = {
        count: 2,
        gallery: {},
        isLoading: true,
        next: null,
        paginations: true,
        previous: null,
        results: [{}, {}]

};

So your DELETE_GALLERY_SUCCCESS case must be like this if you want to remove a image in results array.

   case DELETE_GALLERY_SUCCESS:
           return {
                ...state,
                  isLoading: false,
                  results: state.results.filter(image => image.id !== action.payload)
                }
            };

Ad
source: stackoverflow.com
Ad