t13n
t13n

Reputation: 362

this.setState is not working correctly

I am using React 16 with Redux and i am using this.setState func onClick. But it is not working correctly. I tried to debug for hours and could not find any solution. Here is my code;

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class SSelect extends Component {
    state = {
        selectedName: '',
    }

    handleSelect = (id, name) => {
        this.setState({ selectedName: name });
        this.props.handleSelect(id); // this is redux action
    }

    render() {
        console.log(this.state.selectedName);
        return (
            <div>
                {
                    this.props.options.map(option => (
                        <div
                            key={option.id}
                            role="button"
                            onKeyPress={() => this.handleSelect(option.id, option.name)}
                            onClick={() => this.handleSelect(option.id, option.name)}
                            tabIndex="0"
                        >
                            {option.name}
                        </div>
                    ))
                }
            </div>
        );
    }
}

SSelect.propTypes = {
    handleSelect: PropTypes.func.isRequired,
    options: PropTypes.array.isRequired,
    segmentIndex: PropTypes.number,
};

SSelect.defaultProps = {
    segmentIndex: 0,
};

export default onClickOutside(SSelect);

console.log(this.state.selectedName); prints nothing, if i select same option on list, it prints true result. After select a new option, it prints empty again.

when i track my redux processes, i saw that it is working and sets new value to store correctly. when i remove my redux action, console.log(this.state.selectedName); printing true value.

here is my react and redux versions;

"react": "^16.2.0",
"react-redux": "^5.0.6",
"redux": "^3.7.2",

Thank you for your help.

Upvotes: 0

Views: 124

Answers (4)

Gamsh
Gamsh

Reputation: 545

To solve this problem a simple way, You can set the selectedName manually and then you can do force update.

handleSelect(id, name) {
this.state.selectedName=name;
this.forceUpdate();
this.props.handleSelect(id);
}

To redux setState
handleSelect(id,name){ this.setState({ selectedName: name }) };

onClick={this.handleSelect.bind(this,option.id, option.name)}

Upvotes: 1

t13n
t13n

Reputation: 362

This is very strange but i solved the problem.

On my reducer, my key's name was segment. I converted the name to selectedSegment and problem solved. I think segment word is reserved but i could not find any doc about reserved words.

I will open an issue to react-redux

Thank you all

Upvotes: 0

Daniel Khoroshko
Daniel Khoroshko

Reputation: 2721

I suppose you wrap the component with connect()?

As far is I know connect() makes you component pure (in redux terminology - props only) by default. It can be overridden in the fourth options argument of connect.

However most likely the best solution would be to get rid of internal state, because that's what we use redux for

[options] (Object) If specified, further customizes the behavior of the connector. In addition to the options passable to connectAdvanced() (see those below), connect() accepts these additional options:

[pure] (Boolean): If true, connect() will avoid re-renders and calls to mapStateToProps, mapDispatchToProps, and mergeProps if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: true

https://github.com/reactjs/react-redux/blob/master/docs/api.md

Upvotes: 0

Adam Jenkins
Adam Jenkins

Reputation: 55643

Unless my eyes are deceiving me, you have defined handleSelect as a class method and not an instance method meaning the this inside of the handleSelect function you have defined does not refer to your component.

You should define it as:

handleSelect(id, name) {
    this.setState({ selectedName: name });
    this.props.handleSelect(id); // this is redux action
}

rather than:

handleSelect = (id, name) => {
    this.setState({ selectedName: name });
    this.props.handleSelect(id); // this is redux action
}

Upvotes: 0

Related Questions