Can't get store value after the value was updated using React


Can't get store value after the value was updated using React



I have a SearchBar component and it has a subcomponent SearchBarItem.



I passed the method handleSelectItem() to subcomponent to dispatch value to store and it works (I saw it from the Redux tool in Chrome).


handleSelectItem()



Then, when I tried to get the value from the method submitSearch(), which I also passed it from the parent component, it shows:


submitSearch()


Cannot read property 'area' of undefined.



I'm still not so familiar with React. If someone can help, it will be very appreciated. Thanks in advance.



This is parent component SearchBar:


class SearchBar extends Component {
handleSelectItem = (selectCategory, selectedItem) => {
if (selectCategory === 'areas') {
this.props.searchActions.setSearchArea(selectedItem);
}
}

submitSearch() {
console.log(this.props.area); // this one is undefined
}

render() {
return (
<div className="searchBar">
<SearchBarItem
selectCategory="areas"
name="地區"
options={this.props.areaOptions}
handleSelectItem={this.handleSelectItem}
submitSearch={this.submitSearch}
/>
</div>
);
}
}

const mapStateToProps = state => ({
area: state.search.area,
brandOptions: state.search.brandOptions,
vehicleTypeOptions: state.search.vehicleTypeOptions,
areaOptions: state.search.areaOptions,
});

const mapDispatchToProps = dispatch => ({
searchActions: bindActionCreators(searchActions, dispatch),
});

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



This is subcomponent SearchBarItem:


export default class SearchBarItem extends Component {
state = {
showOptions: false,
selectedItem: ,
}

handleSelectItem = (selectedItem) => this.props.handleSelectItem(this.props.selectCategory, selectedItem);

submitSearch = () => this.props.submitSearch();

handleClickCategory = () => {
this.setState({ showOptions: !this.state.showOptions });
}

handleClickItem(option) {
this.setState({
selectedItem: [...this.state.selectedItem, option],
}, () => this.handleSelectItem(this.state.selectedItem));
}

render() {
const options = this.props.options.map((item, index) => (
<div
className={this.state.selectedItem === item ? "searchBarItem__option--active" : "searchBarItem__option"}
key={index}
onClick={() => this.handleClickItem(item)}
>
{item}
</div>
));

const optionBox = (
<div className="searchBarItem__box">
<div
className="searchBarItem__option"
onClick={() => this.handleClickItem('')}
>
不限{this.props.name}
</div>
{options}
<div className="searchBarItem__confirm">
<span>取消</span><span onClick={() => this.submitSearch()} >套用</span>
</div>
</div>
);

return (
<div className="searchBarItem">
<span onClick={() => this.handleClickCategory()} >
{(() => {
switch (this.state.selectedItem.length) {
case 0: return this.props.name;
case 1: return this.state.selectedItem[0];
default: return `${this.state.selectedItem.length} ${this.props.name}`;
}
})()}
</span>
{ this.state.selectedItem.length > 0 ? '' : <Icon icon={ICONS.DROP_DOWN} size={18} /> }
{ this.state.showOptions ? optionBox : '' }
</div>
);
}
}

SearchBarItem.propTypes = {
name: PropTypes.string.isRequired,
selectCategory: PropTypes.string.isRequired,
options: PropTypes.arrayOf(PropTypes.string).isRequired,
handleSelectItem: PropTypes.func.isRequired,
submitSearch: PropTypes.func.isRequired,
};





change submitSearch() { console.log(this.props.area); // this one is undefined } to submitSearch = () => { console.log(this.props.area); } Can explain later (writing it via the phone now)
– Daniel Krom
Jul 1 at 7:58



submitSearch() { console.log(this.props.area); // this one is undefined }


submitSearch = () => { console.log(this.props.area); }





it works! thank you so much! And yes, if you can explain later will be super helpful!
– J.H
Jul 1 at 8:05




1 Answer
1



Your problem caused by the behavior of this pointer in javascript.


this



By writing the code submitSearch={this.submitSearch} you are actually sending a pointer to the submitSearch method but losing the this pointer.


submitSearch={this.submitSearch}


submitSearch


this



The method actually defers as MyClass.prototype.myMethod. By sending a pointer to the method MyClass.prototype.myMethod you are not specifying to what instance of MyClass it belongs to (if at all). This is not the most accurate explanation of how this pointer works but it's intuitive explanation, you can read more here about how this pointer works


MyClass.prototype.myMethod


MyClass.prototype.myMethod


MyClass


this


this



You have some possible options to solve it:



Option one - define methods as class variable


class MyClass{
myMethod = () => {
console.log(this instanceof MyClass) // true
}
}



By this way, you are sending a pointer to the variable (that points to a method)



Option two - Bind the method on the constructor


class MyClass{
constructor(){
this.myMethod = this.myMethod.bind(this)
}
myMethod() {
console.log(this instanceof MyClass) // true
}
}



By the second way, you are binding the method to current this instance



Small note, you should avoid doing:


<MyComponent onSomeCallback={this.myCallback.bind(this)} />



Function.prototype.bind returns a new method and not mutating the existing one, so each render you'll create a new method and it has performance impact on render (binding it on the constructor only once as option two, is fine)


Function.prototype.bind





Thank you for the explanation. I used binding the pointer on other places but without knowing what's that mean. Big help, thank you so much.
– J.H
Jul 2 at 2:39






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API