Categories
React Tips

React Tips — Input Event, Redux, Forward Ref and Bubbling

Spread the love

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Best Way to Trigger Change Event in React

We can trigger events programmatically by getting the native input value setter.

Then we can trigger the input event with it instead of React’s version.

For instance, we can write:

const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'something');

const ev = new Event('input', { bubbles: true });
input.dispatchEvent(ev);

We get the native input value setter with:

const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;

Then we create a native input event by writing:

nativeInputValueSetter.call(input, 'something');

The first argument is the input element.

The 2nd is the value of the input.

Then we created the event with:

const ev = new Event('input', { bubbles: true });

And then we dispatch the input event on the input element with:

input.dispatchEvent(ev);

Prevent Event Bubbling in Nested Components on Click

We can prevent event bubbling in nested components on click by using the stopProphation method.

For instance, we can write:

class ListItem extends React.Component {
  constructor(){
    super();
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.stopPropagation();
    this.props.onClick();
  }

  render() {
    return (
      <li onClick={this.handleClick}>
        {this.props.children}
      </li>
    )
  }
}

class List extends React.Component {
  constructor(){
    super();
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    // ...
  }
  render() {
    return (
      <ul onClick={this.handleClick}>
        <ListItem onClick={this.handleClick}>Item</ListItem>
      </ul>
    )
  }
}

Since we have a click listen for the ul element and multiple click listeners for the li elements, we’ve to call stopPropagation on the li elements’ click handlers so that the click event won’t bubble up to the ul element and beyond.

We did that with:

e.stopPropagation();

in the handleClick method of ListItem .

Use React.forwardRef in a Class-Based Component

We can use React.forwardRef in a class-based component by passing in a callback that returns the class-based component inside.

For instance, we can write:

class DivComponent extends Component {
  render() {
    return (
      <div ref={this.props.innerRef}>
        foo
      </div>
    )
  }
}

const Comp = React.forwardRef((props, ref) => <DivComponent
  innerRef={ref} {...props}
/>);

We pass in a callback with the props and ref parameters and we return the DivComponent with the props and ref passed in as props of it.

Then we can access the ref by referencing the this.props.innerRef so that we can assign it as the ref of the div.

Simple Dispatch from this.props Using connect with Redux

We can map our dispatch functions to props by using the mapDispatchToProps method.

For instance,e we can write:

const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => dispatch(decrement())
  };
}

to map the dispatch call for the decrement action to the onClick prop.

We can also put the dispatch function into the object to access it directly:

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
    onClick: () => dispatch(decrement())
  };
}

We can also use bindActionCreators to turn:

function mapDispatchToProps(dispatch) {
  return {
    onPlusClick: () => dispatch(increment()),
    onMinusClick: () => dispatch(decrement())
  };
}

to:

import { bindActionCreators } from 'redux';

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({
    onPlusClick: increment,
    onMinusClick: decrement
  }, dispatch);
}

We mapped the increment and decrement actions to the onPlusClick and onMinusClick props.

And we can shorten that to:

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ increment, decrement }, dispatch);
}

Then we just get the increment and decrement from the props and call them to dispatch the actions.

We can shorten it even more by turning:

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ increment, decrement }, dispatch);
}

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

Into:

export default connect(
  mapStateToProps,
  { increment, decrement }
)(App);

This will inject increment and decrement as props without mapDispatchToProps .

Update Single Value Inside Specific Array Item in Redux

We can update a single value inside a specific array item in Redux writing our reducer in a way that divides the array, modifies the entry we want to change, and join them back together.

For instance, we can write:

case 'MODIFY_ARRAY':
   return {
       ...state,
       contents: [
          ...state.contents.slice(0, index),
          { title: "title", text: "text" },
         ...state.contents.slice(index + 1)
       ]
    }

We called slice to divide the array into chunks. Then we have our next object between the chunks.

Then we use the speed operator to join them back together into one array.

Conclusion

There are many shorthands for mapDispatchToProps .

We can change an array entry by returning a new array in a reducer.

We can call stopPropagation to stop event bubbling.

Also, we can trigger an input event programmatically with the native input value setter.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *