Sachin Bhandari
Sachin Bhandari

Reputation: 566

React-Redux: Component didn't re-render even props are changed

I had a problem in component re-rendering even props are changed. I had a reducer(below) which handles the state of a photo album and uploading of any new photo in that.

    const profilePhotoReducer = (state={
    fetching: false,
    photos: [],
    dataSetChanged: false,
    uploading: false
},action)=>{
    console.log('reducer called: ', action.type);
    switch (action.type){
        case "PHOTOS_FETCHING":
            return{
                ...state,
                fetching: true
            };

        case "PHOTOS_FETCH_SUCCESS":
            return {
                ...state,
                fetching: false,
                photos: action.payload,
                dataSetChanged: false
            };

        case "PHOTOS_FETCH_FAILED":
            return {
                ...state,
                fetching: false,
                dataSetChanged: false
            };

        case "UPLOADING":
            return {
                ...state,
                uploading: true
            };

        case "UPLOAD_SUCCESS":
            return {
                ...state,
                dataSetChanged: true,
                uploading: false
            };

        case "UPLOAD_FAILED":
            return {
                ...state,
                uploading: false
            };

        default:
            return state;
    }
};

export default profilePhotoReducer;

after the successful photo upload the 'UPLOAD_SUCCESS' action.type is matched and flips the dataSetChanged(Boolean) and in my component(below) I'm handling it this way:

    class ProfilePhotosComponent extends React.Component{
    componentDidMount(){
        console.log('********------***********: ', this.props.profilePhoto.dataSetChanged);
        if(this.props.profilePhoto.photos.length === 0 || this.props.profilePhoto.dataSetChanged){
            this.props.getPhotos();
        }
    }

    render(){

        const PhotoList = this.props.profilePhoto.photos.map((photo, i)=>{
            return (<PhotoComponent name={photo} key={i}/>);
        });

        return (
            <div className={'card pcard'}>
                <div className={'col-md-12'}>
                    <UploadPhotoForm handleUpload={this.props.handleUpload}/>
                    {PhotoList}
                </div>
            </div>
        );
    }
}

function mapStateToProps(state){
    return {
        profilePhoto: state.profilePhoto
    };
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({
        getPhotos,
        handleUpload
    },dispatch);
}

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

Upvotes: 0

Views: 579

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281666

The thing is that componentDidMount function is called only once after component has mounted, after that if the props change, your component is re-rendered but your photos are not fetched again and hence you don't see a difference, what you need is componentWillReceiveProps

componentWillReceiveProps(nextProps) {
    console.log('********------***********: ', nextProps.profilePhoto.dataSetChanged);

    if(this.props.profilePhoto.dataSetChanged !== nextProps.profilePhoto.dataSetChanged) {
        if(nextProps.profilePhoto.photos.length === 0 || nextProps.profilePhoto.dataSetChanged){
            this.props.getPhotos();
        }
     }
 }

Upvotes: 1

Rukshan
Rukshan

Reputation: 8066

In your mapStateToProps I don't see that you have dataSetChanged returned like this.

function mapStateToProps(state){
    return {
       dataSetChanged: state. dataSetChanged
    };
}

And ComponentDidMount will not get called when props are updated, You have to either use componentWillReceiveProps() or directly bind that property to a JSX element in your render function.

Upvotes: 0

Related Questions