Jeffrey04
Jeffrey04

Reputation: 6338

Binding event handler prop with react-redux

What is the proper way to declare event handler from container to the presentation widget so that I can access other props in the event handler function?

class ApplicationWidget extends Component {
    componentDidMount() {
        this.props.handle_onload.call(this);
    }

    render() {
        return (
            <div onClick={this.props.handle_click}>
                <Header />
                <Content />
            </div>
        );
    }
}

export default connect(
    state => {
        return {foo: state.foo};
    },
    dispatch => {
        return {
            handle_click() {
                console.log(this)
            },
            handle_onload() {
                jQuery.get({
                    accepts: 'application/json',
                    success: (data) => dispatch(the_action_creator(data)),
                    url: `/initialize`
                });
            }
        };
    }
)(ApplicationWidget);

Currently the this.props.handle_click event handler logs undefined whenever the click event happens. If I want access to this.props.foo, what is the right way of doing it? My current implementation is

<div onClick={this.props.handle_click.bind(this)}>

in the render() method and it works as intended however according to the linter this doesn't look like a good practice. The following code doesn't seem to work after the container (generated by the connect function) is updated (the binding is reseted to undefined for some reason)

constructor(props) {
    super(props);
    this.props.handle_click = this.props.handle_click.bind(this)
}

So what is the right way to do this? Or am I doing this whole thing wrong?

Upvotes: 1

Views: 553

Answers (1)

Patrick Hund
Patrick Hund

Reputation: 20256

The prop handle_click is just a function that is passed to the component by reference, so it doesn't “know” anything about the scope (this) of the component. You can change that using the bind method that is available to all functions, like this:

class ApplicationWidget extends Component {
    componentDidMount() {
        this.props.handle_onload.call(this);
    }

    render() {
        return (
            <div onClick={this.props.handle_click.bind(this)}>
                <Header />
                <Content />
            </div>
        );
    }
}

To optimize this and prevent your linter from complaining, you can bind it in the constructor like this:

class ApplicationWidget extends Component {
    constructor(props) {
        super(props);
        this.handle_click = props.handle_click.bind(this);
    }

    componentDidMount() {
        this.props.handle_onload.call(this);
    }

    render() {
        return (
            <div onClick={this.handle_click}>
                <Header />
                <Content />
            </div>
        );
    }
}

So you almost got it right, but I wouldn't modify the props in the constructor, just add another method to the class.

Upvotes: 2

Related Questions