0
votes

My component State is not being update with Reducer, in mapStateToProps get Reducer State well and appears in the props but shouldn't it update the State of my Component for it to re-render? In Reducer returning the state {...state, rows:news_formated.slice(0,30)} with Spread syntax from the docs and comments all say this one of the methods to use to return a new instance of the state and not alter the state itself. Below is the code for Action, Reducer and part of my component code.


class CreateGenericTable extends Component {    

    constructor(props){
        super(props);
        this.state = {  rows:null, columns:null};
    } 

    componentDidMount(){

        var token = getCookie('admin_session_token');
        servicerequest = this.props.serviceRequest;

        this.setState({columns: this.props.columns})

        var teste = this.props.tableList(this.props.editform,this.props.service,token,servicerequest,this.props.columns)
        console.log(this.props);
    }
}  

function mapDispatchToProps(dispatch){
    return bindActionCreators({ tableList, editComponent }, dispatch);
}

const mapStateToProps = (state,ownProps) => { 
    console.log('this is state');
    //console.log(state);

    if(state.tabledata.rows!=null){
        debugger;
        return { rows: state.tabledata.rows};
    }else{
        return { rows: null};
    }

};

//export default connect(null, mapDispatchToProps)(CreateGenericTable)
const CreateGenericTableRedux = connect(mapStateToProps, mapDispatchToProps)(CreateGenericTable)

Action

import $ from "jquery";//https://redux.js.org/docs/advanced/AsyncActions.html Asynchronous calls need to use thunk of redux.....

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

export const FETCH_TABLEDATA = 'FETCH_TABLEDATA'
export const EDIT_COMP = 'EDIT_COMP'

export function editComponent(id,View){
    return {
        type: EDIT_COMP,
        payload: {'id':id,'View':View}
    }
}

export function tableList(editform,service,token,serviceRequest){

    var request = null;

    return dispatch => {
        $.ajax({
            type: "POST",
            url: service,
            crossDomain: true,
            dataType: 'jsonp',
            xhrFields: {
                withCredentials: true
            },
            data: { 
                q: JSON.stringify({
                    [serviceRequest]:{}
                }),
                admin_session_token:token, 
            },
            success : (data) => {   
                request = data;
                dispatch({
                    type: FETCH_TABLEDATA,
                    payload: {editform: editform,request: request, serviceRequest: serviceRequest }
                });            
            },

            error: (xhr, status, err) =>{
                ////console.log('ups somehting went rong:'.err.toString());
            },

        }); 
    };          

    /*
    return request.then ({
        type: FETCH_TABLEDATA,
        payload: {request: request, serviceRequest: serviceRequest, columns: columns}
    });
    */

}

Reducer

import { FETCH_TABLEDATA } from '../actions/index.js'

//const INITIAL_STATE = {rows:null, columns:[]} //separate the data proprocessing to a function -> https://gist.github.com/abhiaiyer91/aaf6e325cf7fc5fd5ebc70192a1fa170

export default function(state = [], action){    switch(action.type){        case FETCH_TABLEDATA:
            var data = action.payload.request[action.payload.serviceRequest];//var data = data['News_get'];
            console.log('----state---');            console.log(state);

            if(data.length>0){
                var news_formated = [];
                var listofkeys = Object.keys(data[0]);

                for(var new_unformated of data){
                    var new_formated = [];
                    //console.log(new_unformated);
                    for(var key of listofkeys){

                        //console.log(key);
                        if(action.payload.editform.indexOf('EditHeader') !== -1 && key.indexOf('language_items') !== -1){
                            new_formated['image'] = new_unformated[key][0]['image'];
                            new_formated['link'] = new_unformated[key][0]['link'];
                        }else{

                            if(action.payload.editform.indexOf('EditNotification') !== -1){
                                if(key.indexOf('params') !== -1){
                                    new_formated[key] = new_unformated[key]['message'];
                                }else{
                                    new_formated[key] = new_unformated[key];
                                }
                            }else{
                                if(key.indexOf('active') !== -1){
                                    if(new_unformated[key].indexOf('1') !== -1){
                                        new_formated[key] = 'Yes';
                                    }else{
                                        new_formated[key] = 'No';
                                    }
                                }else{
                                    new_formated[key] = new_unformated[key];
                                }
                            }

                        }


                    }

                    news_formated.push(new_formated);

                }

                return {
                            ...state,
                            rows:news_formated.slice(0,30)
                        };
            }else{
                return {
                            ...state,
                            rows:null
                    };
            }
            //{...state, {rows:null, columns:action.payload.columns}};      default:            return {
                            ...state,
                            rows:null
                    };  } }
1

1 Answers

2
votes

componentDidMount function is called only on first render when then component mounts and hence any further update in redux store, reflected in props to the component won't be set to state in your implementation. You would need to implement the same logic in componentWillReceiveProps function

Also to remind you its an anti-pattern to have a state that is directly derivable from props, you should use the props directly instead.

although you could achieve what you want like

class CreateGenericTable extends Component {    

    constructor(props){
        super(props);
        this.state = {  rows:null, columns:null};
    } 

    componentDidMount(){

        var token = getCookie('admin_session_token');
        servicerequest = this.props.serviceRequest;

        this.setState({columns: this.props.columns})

        var teste = this.props.tableList(this.props.editform,this.props.service,token,servicerequest,this.props.columns)
        console.log(this.props);
    }
    componentWillReceiveProps(nextProps) {
         if(nextProps.columns !== this.props.columns) { // You might need to have a deep comparison here if columns is not immutable or a nested obejct. You can use _.isEqual from lodash in that case
             this.setState({columns: nextProps.columns})
         }
    }
}  

function mapDispatchToProps(dispatch){
    return bindActionCreators({ tableList, editComponent }, dispatch);
}

const mapStateToProps = (state,ownProps) => { 
    console.log('this is state');
    //console.log(state);

    if(state.tabledata.rows!=null){
        debugger;
        return { rows: state.tabledata.rows};
    }else{
        return { rows: null};
    }

};

export default connect(null, mapDispatchToProps)(CreateGenericTable)

I would strictly advice you to use this.props.columns directly in your component if possible instead of keeping it in state