javascript - accessing props inside react constructor - Stack Overflow

I am unable to get props inside constructor that I have implemented using redux concept.Code for contai

I am unable to get props inside constructor that I have implemented using redux concept.

Code for container ponent

class UpdateItem extends Component{
    constructor(props) {
    super(props);
    console.log(this.props.item.itemTitle) // output: undefined
    this.state = {
        itemTitle: this.props.item.itemTitle,
        errors: {}
    };

    this.handleChange = this.handleChange.bind(this);
}

handleChange(e) {
    //If the input fields were directly within this
    //this ponent, we could use this.refs.[FIELD].value
    //Instead, we want to save the data for when the form is submitted
    let state = {};
    state[e.target.name] = e.target.value.trim();
    this.setState(state);
}

    handleSubmit(e) {
    //we don't want the form to submit, so we pritem the default behavior
    e.preventDefault();

    let errors = {};
    errors = this._validate();
    if(Object.keys(errors).length != 0) {
        this.setState({
            errors: errors
        });
        return;
    }
    let itemData = new FormData();
    itemData.append('itemTitle',this.state.itemTitle)

    this.props.onSubmit(itemData);
}

    ponentDidMount(){
        this.props.getItemByID();
    }

    ponentWillReceiveProps(nextProps){
        if (this.props.item.itemID != nextProps.item.itemID){
            //Necessary to populate form when existing item is loaded directly.
            this.props.getItemByID();
        }
    }


    render(){

        let {item} = this.props;
        return(
            <UpdateItemForm
            itemTitle={this.state.itemTitle}
            errors={this.state.errors}
            />
        );
    }
}

UpdateItem.propTypes = {
    item: PropTypes.array.isRequired
};

function mapStateToProps(state, ownProps){
    let item = {
        itemTitle: ''
    };


    return {
        item: state.itemReducer
    };
}

function mapDispatchToProps (dispatch, ownProps) {
    return {
        getItemByID:()=>dispatch(loadItemByID(ownProps.params.id)),
        onSubmit: (values) => dispatch(updateItem(values))
    }
}

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

Inside render() method am able to get the props i.e. item from the redux but not inside constructor.

And code for the actions to see if the redux implementation correct or not,

    export function loadItemByID(ID){
        return function(dispatch){
            return itemAPI.getItemByID(ID).then(item => {
                dispatch(loadItemByIDSuccess(item));
            }).catch(error => {
                throw(error);
            });
        };
    }

export function loadItemByIDSuccess(item){
    return {type: types.LOAD_ITEM_BY_ID_SUCCESS, item}
}

Finally my reducer looks as follows,

export default function itemReducer(state = initialState.item, action) {
    switch (action.type) {
        case types.LOAD_ITEM_BY_ID_SUCCESS:
            return Object.assign([], state = action.item, {
                item: action.item
            });
        default:
            return state;
    }
}

I have googled to get answers with no luck, I don't know where i made a mistake. If some one point out for me it would be a great help. Thanks in advance.

I am unable to get props inside constructor that I have implemented using redux concept.

Code for container ponent

class UpdateItem extends Component{
    constructor(props) {
    super(props);
    console.log(this.props.item.itemTitle) // output: undefined
    this.state = {
        itemTitle: this.props.item.itemTitle,
        errors: {}
    };

    this.handleChange = this.handleChange.bind(this);
}

handleChange(e) {
    //If the input fields were directly within this
    //this ponent, we could use this.refs.[FIELD].value
    //Instead, we want to save the data for when the form is submitted
    let state = {};
    state[e.target.name] = e.target.value.trim();
    this.setState(state);
}

    handleSubmit(e) {
    //we don't want the form to submit, so we pritem the default behavior
    e.preventDefault();

    let errors = {};
    errors = this._validate();
    if(Object.keys(errors).length != 0) {
        this.setState({
            errors: errors
        });
        return;
    }
    let itemData = new FormData();
    itemData.append('itemTitle',this.state.itemTitle)

    this.props.onSubmit(itemData);
}

    ponentDidMount(){
        this.props.getItemByID();
    }

    ponentWillReceiveProps(nextProps){
        if (this.props.item.itemID != nextProps.item.itemID){
            //Necessary to populate form when existing item is loaded directly.
            this.props.getItemByID();
        }
    }


    render(){

        let {item} = this.props;
        return(
            <UpdateItemForm
            itemTitle={this.state.itemTitle}
            errors={this.state.errors}
            />
        );
    }
}

UpdateItem.propTypes = {
    item: PropTypes.array.isRequired
};

function mapStateToProps(state, ownProps){
    let item = {
        itemTitle: ''
    };


    return {
        item: state.itemReducer
    };
}

function mapDispatchToProps (dispatch, ownProps) {
    return {
        getItemByID:()=>dispatch(loadItemByID(ownProps.params.id)),
        onSubmit: (values) => dispatch(updateItem(values))
    }
}

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

Inside render() method am able to get the props i.e. item from the redux but not inside constructor.

And code for the actions to see if the redux implementation correct or not,

    export function loadItemByID(ID){
        return function(dispatch){
            return itemAPI.getItemByID(ID).then(item => {
                dispatch(loadItemByIDSuccess(item));
            }).catch(error => {
                throw(error);
            });
        };
    }

export function loadItemByIDSuccess(item){
    return {type: types.LOAD_ITEM_BY_ID_SUCCESS, item}
}

Finally my reducer looks as follows,

export default function itemReducer(state = initialState.item, action) {
    switch (action.type) {
        case types.LOAD_ITEM_BY_ID_SUCCESS:
            return Object.assign([], state = action.item, {
                item: action.item
            });
        default:
            return state;
    }
}

I have googled to get answers with no luck, I don't know where i made a mistake. If some one point out for me it would be a great help. Thanks in advance.

Share Improve this question asked Apr 22, 2017 at 12:57 poisepoise 8671 gold badge9 silver badges16 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

The reason you can't access the props in the constructor is that it is only called once, before the ponent is first mounted.

The action to load the item is called in the ponentWillMount function, which occurs after the constructor is called.

It appears like you are trying to set a default value in the mapStateToProps function but aren't using it at all

function mapStateToProps(state, ownProps){
    // this is never used
    let item = {
        itemTitle: ''
    };


    return {
        item: state.itemReducer
    };
}

The next part I notice is that your are taking the state from redux and trying to inject it into the ponent's local state

this.state = {
    itemTitle: this.props.item.itemTitle,
    errors: {}
};

Mixing redux state and ponent state is very rarely a good idea and should try to be avoided. It can lead to inconsistency and and hard to find bugs.

In this case, I don't see any reason you can't replace all the uses of this.state.itemTitle with this.props.items.itemTitle and remove it pletely from the ponent state.


Observations

There are some peculiar things about your code that make it very difficult for me to infer the intention behind the code.

Firstly the reducer

export default function itemReducer(state = initialState.item, action) {
    switch (action.type) {
        case types.LOAD_ITEM_BY_ID_SUCCESS:
            return Object.assign([], state = action.item, {
                item: action.item
            });
        default:
            return state;
    }
}

You haven't shown the initialState object, but generally it represents the whole initial state for the reducer, so using initialState.item stands out to me. You may be reusing a shared initial state object for all of the reducers so I'm not too concerned about this.

What is very confusing the Object.assign call. I'm not sure it the intention is to output an object replacing item in the state, or if it is to append action.item to an array, or to have an array with a single item as the resulting state. The state = action.item part is also particularly puzzling as to it's intention in the operation.

This is further confused by the PropTypes for UpdateItem which requires item to be an array

UpdateItem.propTypes = {
    item: PropTypes.array.isRequired
};

But the usage in the ponent treats it like and object

this.state = {
  // expected some kind of array lookup here |
  //                          V---------------
    itemTitle: this.props.item.itemTitle,
    errors: {}
};

Update from ments

Here is a example of what I was talking about in the ments. It's a simplified version of your code (I don't have all your ponents. I've also modified a few things to match my personal style, but hopefully you can still see what's going on.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744498883a4577311.html

相关推荐

  • javascript - accessing props inside react constructor - Stack Overflow

    I am unable to get props inside constructor that I have implemented using redux concept.Code for contai

    1天前
    50

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信