Marc Fearby
Marc Fearby

Reputation: 1384

How to create a React component in TypeScript that lets me handle an event?

I would like to create a custom component in React using TypeScript that's essentially a combobox which has auto-complete/search functionality, connecting to its own remote store. What I would like to do is send an "onSelect" event so that I can receive the selected item where ever I'm using that component in my app.

Doing the auto-complete/search stuff with the remote store is easy, but the React component stuff has me stumped. I'm still learning both, so perhaps I'm trying to walk before I can crawl, but I don't want to start out creating a mess when I know that it should be possible to achieve this outcome which would be more elegant. I just need to find some sort of guide, but so far I haven't found one.

Here's what I want to achieve:

<MyCombobox onSelect={handleSelect} />

The handleSelect function would be used throughout my app where ever I need to use the MyCombobox component. The function needs to accept an argument, of course (which is what has me stumped at the moment, in TS).

Upvotes: 0

Views: 373

Answers (2)

Marc Fearby
Marc Fearby

Reputation: 1384

From all the googling I've done this morning, I've managed to cobble together something that works (from a plethora of sources):

App.tsx:

import React from 'react';
import './App.css';

import MyCombobox from './MyCombobox';

class App extends React.Component {

    receiveSomething(something: string) {
        alert('Something: ' + something);
    }

    render() {
        return (
            <div>
                <MyCombobox receiveSomething={this.receiveSomething} defaultValue="qwerty" />
            </div>
        );
    }
}

export default App;

MyCombobox.tsx:

import React from 'react';

export interface IMyCombobox {
    defaultValue: string,
    receiveSomething:(name:string) => void
}

class MyCombobox extends React.PureComponent<IMyCombobox, any> {

    state = {
        something: this.props.defaultValue
    }

    sendSomething() {  
        this.props.receiveSomething(this.state.something);  
    }

    handleChange = (event: any) : void => {
        this.setState({ 
            something: event.target.value
        });
    }

    render() {
        return (
            <div>
                <input 
                    type='text'
                    maxLength={20}
                    value={this.state.something} 
                    onChange={this.handleChange} />

                <input 
                    type='button' 
                    value='Send Something'
                    onClick={this.sendSomething.bind(this)} />
            </div>
        )
    }
}

export default MyCombobox;

Upvotes: 0

Fyodor Yemelyanenko
Fyodor Yemelyanenko

Reputation: 11848

One possible solution is as following

import * as React from "react";
import { render } from "react-dom";

interface MyComboProps {
    // Here props from parent should be defined
}

interface MyComboState {
    ValuesToShow: string[];
    SearchValue: string;
}

class StringSearchMenu extends React.Component<MyComboProps, MyComboState> {
    constructor(p: MyComboProps) {
        super(p);
        this.state = {
            ValuesToShow: [],
            SearchValue: ""
        };
    }

    protected selectString(event: React.ChangeEvent<HTMLInputElement>): void {
        let value = event.target.value;
        if (value === "") this.setState({ ValuesToShow: [] });
        else {
            /* here you can put fetch logic. I use static array as example */
            let possibleValues = ["Green", "Red", "Blue", "Yellow", "Black"];
            this.setState({
                ValuesToShow: possibleValues.filter(f => f.indexOf(value) > -1)
            });
        }
    }

    render() {
        return (
            <div>
                Enter value to search {"   "}
                <input onChange={this.selectString.bind(this)} />
                <div>
                    {this.state.ValuesToShow.map(v => (
                        <div>{v}</div>
                    ))}
                </div>
           </div>
      );
      }
}

And working example is here

Upvotes: 1

Related Questions