Lesson 15-Preact Event Handling

In Preact, event handling follows a pattern similar to React, utilizing a synthetic event system to provide a consistent interface across browsers.

Event Binding

In Preact, event handlers are bound to elements via JSX, using camelCase event names.

Class Component Event Binding

import { Component } from 'preact';

class MyComponent extends Component {
  handleClick = () => {
    console.log('Button clicked!');
  };

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me!
      </button>
    );
  }
}

Function Component Event Binding

Use useRef to maintain function references in function components, avoiding new function instances on each render.

import { useRef, useState } from 'preact/hooks';

function MyComponent() {
  const [count, setCount] = useState(0);
  const handleClick = useRef(() => {
    setCount(count + 1);
  }).current;

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

Common Event Types

Preact supports various event types, including mouse, keyboard, and form events.

Mouse Events

Common mouse events include:

  • onClick
  • onDoubleClick
  • onMouseEnter
  • onMouseLeave
  • onMouseMove
  • onMouseDown
  • onMouseUp

Example:

import { h, Component } from 'preact';

class MouseEvents extends Component {
  handleMouseEnter = () => {
    console.log('Mouse entered');
  };

  handleMouseLeave = () => {
    console.log('Mouse left');
  };

  render() {
    return (
      <div
        onMouseEnter={this.handleMouseEnter}
        onMouseLeave={this.handleMouseLeave}
        style={{ width: '200px', height: '200px', backgroundColor: 'lightblue' }}
      >
        Hover over me
      </div>
    );
  }
}

export default MouseEvents;

Keyboard Events

Common keyboard events include:

  • onKeyDown
  • onKeyUp
  • onKeyPress

Example:

import { h, Component } from 'preact';

class KeyEvents extends Component {
  handleKeyDown = (event) => {
    console.log(`Key pressed: ${event.key}`);
  };

  render() {
    return <input type="text" onKeyDown={this.handleKeyDown} />;
  }
}

export default KeyEvents;

Form Events

Common form events include:

  • onChange
  • onInput
  • onSubmit

Example:

import { h, Component } from 'preact';

class FormEvents extends Component {
  handleChange = (event) => {
    console.log(`Input changed: ${event.target.value}`);
  };

  handleSubmit = (event) => {
    event.preventDefault();
    console.log('Form submitted');
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="text" onChange={this.handleChange} />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

export default FormEvents;

Other Events

Other common events include:

  • onFocus
  • onBlur
  • onResize
  • onScroll

Example:

import { h, Component } from 'preact';

class FocusBlurEvents extends Component {
  handleFocus = () => {
    console.log('Input focused');
  };

  handleBlur = () => {
    console.log('Input blurred');
  };

  render() {
    return <input type="text" onFocus={this.handleFocus} onBlur={this.handleBlur} />;
  }
}

export default FocusBlurEvents;

Event Handling Techniques

Passing Parameters

To pass additional parameters to event handlers, use arrow functions or the bind method.

import { h, Component } from 'preact';

class ParameterPassing extends Component {
  handleClick = (id, event) => {
    console.log(`Button ${id} clicked`);
  };

  render() {
    return (
      <button onClick={(event) => this.handleClick(1, event)}>Click me</button>
    );
  }
}

export default ParameterPassing;

Using this

In class components, ensure event handlers are bound to the correct this context using arrow functions or binding in the constructor.

import { h, Component } from 'preact';

class ThisBinding extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log('Button clicked', this);
  }

  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}

export default ThisBinding;

Event Object

Preact’s event object is similar to the native DOM event object but encapsulated for compatibility and performance.

Accessing the Event Object

handleClick = (event) => {
  console.log(event.target); // Access the element that triggered the event
};

Event Delegation

Event delegation optimizes event handling by attaching a single listener to a parent element instead of individual listeners on each child.

Using Event Delegation

<div id="list">
  {/* List of child elements */}
</div>

handleClick = (event) => {
  if (event.target.tagName === 'BUTTON') {
    console.log('Button clicked!');
  }
};

render() {
  return (
    <div id="list" onClick={this.handleClick}>
      {/* List of child elements */}
    </div>
  );
}

Preventing Event Bubbling and Default Behavior

  • Prevent Bubbling: Use event.stopPropagation().
  • Prevent Default Behavior: Use event.preventDefault().
handleClick = (event) => {
  event.stopPropagation();
  event.preventDefault();
};

Removing Event Listeners

While Preact manages most event listeners automatically, you may need to manually remove them in certain cases.

Removing Listeners on Component Unmount

componentWillUnmount() {
  window.removeEventListener('scroll', this.handleScroll);
}

Using Custom Events

Preact supports custom events for passing complex data between components.

Dispatching Custom Events

fireCustomEvent = () => {
  this.dispatchEvent(new CustomEvent('myEvent', { detail: { message: 'Hello' } }));
};

Listening for Custom Events

componentDidMount() {
  this.addEventListener('myEvent', this.handleMyEvent);
}

handleMyEvent = (event) => {
  console.log(event.detail.message);
};

Handling Events with Hooks

Hooks simplify event and state handling in function components.

import { h } from 'preact';
import { useState } from 'preact/hooks';

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
};

export default Counter;
Share your love