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.