user5948213
user5948213

Reputation:

Why is this undefined within reactjs component method

I have a simple search bar which uses a react-autosuggest. When I create a suggestion, I want to attach an onClick handler. This onClick has been passed down from a parent class. When the suggestion is rendered however, this is undefined and therefore the click handler is not attached.

I have attached the component below, the logic which is not working is in the renderSuggestion method.

import Autosuggest from 'react-autosuggest'
import React from 'react'


export class SearchBar extends React.Component {
     static getSuggestionValue(suggestion) {
        return suggestion;
    }


    static escapeRegexCharacters(str) {
        return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    constructor(props) {
        super(props);

        this.state = {
            value: '',
            suggestions: [],
            listOfValues: this.props.tickers
        };

    }

    onChange = (event, { newValue, method }) => {
        this.setState({
            value: newValue
        });
    };

    onSuggestionsFetchRequested = ({ value }) => {
        this.setState({
            suggestions: this.getSuggestions(value)
        });
    };

    onSuggestionsClearRequested = () => {
        this.setState({
            suggestions: []
        });
    };

    renderSuggestion(suggestion) {
        return (
            <span onClick={() => this.props.clickHandler(suggestion)}>{suggestion}</span>
        );
    }



    getSuggestions(value) {
        const escapedValue = SearchBar.escapeRegexCharacters(value.trim());

        if (escapedValue === '') {
            return [];
        }

        const regex = new RegExp('^' + escapedValue, 'i');

        return this.state.listOfValues.filter(ticker => regex.test(ticker));
    }



    render() {
        const { value, suggestions } = this.state;
        const inputProps = {
            placeholder: "Search for stocks...",
            value,
            onChange: this.onChange
        };

        return (
            <Autosuggest
                suggestions={suggestions}
                onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
                onSuggestionsClearRequested={this.onSuggestionsClearRequested}
                getSuggestionValue={SearchBar.getSuggestionValue}
                renderSuggestion={this.renderSuggestion}
                inputProps={inputProps} />
        );
    }
}

Upvotes: 2

Views: 1275

Answers (2)

Adam Lagevik
Adam Lagevik

Reputation: 683

This is becuase you need to bind "this" to your function. If you add this code to your constructor

constructor(props) {
    super(props);

    this.state = {
        value: '',
        suggestions: [],
        listOfValues: this.props.tickers
    };
    //this line of code binds this to your function so you can use it
    this.renderSuggestion = this.renderSuggestion.bind(this);

}

It should work. More info can be found at https://reactjs.org/docs/handling-events.html

Upvotes: 1

Jamie Dixon
Jamie Dixon

Reputation: 53981

In the scope of renderSuggestion, this isn't referring to the instance of the class.

Turning renderSuggestion into an arrow function like you've done elsewhere will ensure that this refers to the instance of the class.

renderSuggestion = (suggestion) => {
        return (
            <span onClick={() => this.props.clickHandler(suggestion)}>{suggestion}</span>
        );
    }

Upvotes: 0

Related Questions