Hooks contains our logic code in our React app.
We can create our own hooks and use hooks provided by other people.
In this article, we’ll look at some useful React hooks.
react-use
The react-use library is a big library with many handy hooks.
useCustomCompareEffect
We can use the useCustomCompareEffect
hook to let us run a callback after comparing the previous and current value our way.
For instance, we can write:
import React from "react";
import { useCustomCompareEffect, useCounter } from "react-use";
import isEqual from "lodash/isEqual";
export default function App() {
const [count, { inc }] = useCounter(0);
const [options, setOptions] = React.useState({ step: 5 });
useCustomCompareEffect(
() => {
inc(options.step);
},
[options],
(prevDeps, nextDeps) => isEqual(prevDeps, nextDeps)
);
return (
<div>
<button onClick={() => setOptions(({ step }) => ({ step: step + 1 }))}>
increment
</button>
<p>{count}</p>
</div>
);
}
The useCustomCompareEffect
hook takes the 3rd argument with a function to compare the previous and current values of the dependency.
createReducer
We can use the createReducer
function to create a store that we can use with our component.
For instance, we can write:
import React from "react";
import { createReducer } from "react-use";
import logger from "redux-logger";
const initialCount = 0;
const useReducer = createReducer(logger);
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: action.payload };
default:
throw new Error();
}
}
export default function App() {
const [state, dispatch] = useReducer(reducer, { count: initialCount });
return (
<div>
<p>count: {state.count}</p>
<button
onClick={() =>
dispatch({ type: "reset", payload: { count: initialCount } })
}
>
reset
</button>
<button onClick={() => dispatch({ type: "increment" })}>increment</button>
<button onClick={() => dispatch({ type: "decrement" })}>decrement</button>
</div>
);
}
We have a reducer
function that’s like a redux reducer.
It takes an action object that we can use to set the state.
The createReducer
function takes middleware made for Redux and returns the useReducer
hook.
The hook takes our reducer and the initial state.
It then returns an array with the state
and dispatch
variables.
state
has the store state.
dispatch
lets us dispatch actions to the store.
createReducerContext
The createReducerContext
function returns a React context hook that acts like useReducer
except that the state is shared between all components in the provider.
For example, we can write:
import React from "react";
import { createReducerContext } from "react-use";
const initialCount = 0;
const reducer = (state, action) => {
switch (action) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
throw new Error();
}
};
const [useSharedCounter, SharedCounterProvider] = createReducerContext(
reducer,
0
);
const CounterA = () => {
const [count, dispatch] = useSharedCounter();
return (
<div>
<p>count: {count}</p>
<button onClick={() => dispatch("increment")}>increment</button>
<button onClick={() => dispatch("decrement")}>decrement</button>
</div>
);
};
const CounterB = () => {
const [count, dispatch] = useSharedCounter();
return (
<div>
<p>count: {count}</p>
<button onClick={() => dispatch("increment")}>increment</button>
<button onClick={() => dispatch("decrement")}>decrement</button>
</div>
);
};
export default function App() {
return (
<SharedCounterProvider>
<CounterA />
<CounterB />
</SharedCounterProvider>
);
}
We used the createReducerContext
function to return a SharedCounterProvider
.
It takes the reducer and the initial state as the arguments in that order.
This way, we can use the same state across all the components inside the context component.
The useSharedCounter
hook lets us get and set the state.
dispatch
lets us dispatch our actions to the store.
count
has the state.
Conclusion
The react-use library lets us commit side effects in various ways.
It also has hooks to let us share data app-wide.