Simple observer implementation based on React effect hook api, intended for building custom runtime effects.
npm
npm install --save use-custom-effect
yarn
yarn add use-custom-effect
const [useEffectSubscribe, run] = useCustomEffect();
-
useEffectSubscribe
- custom generated hook function based on similar API as React useEffect hook:useEffectSubscribe(callback, deps);
callback
- function that runs every time when custom effect is triggereddeps
- array of values referenced inside the effect callback function
-
run
- function that triggers the custom effect; every argument passed torun
function will be passed touseEffectSubscribe
callback
Basic example
import React, {useEffect} from 'react';
import {useCustomEffect} from 'use-custom-effect';
const EffectProducer = ({run, effectTriggerProp}) => {
useEffect(() => {
run(effectTriggerProp);
}, [effectTriggerProp]);
return null;
}
const EffectConumer = ({useEffectSubscribe}) => {
useEffectSubscribe((value) => {
// this code fragment executes every time when EffectProducer useEffect triggers;
// value - effectTriggerProp passed to run function in EffectProducer
});
return null;
}
const App = () => {
const [useEffectSubscribe, run] = useCustomEffect();
return (
<div>
<EffectProducer run={run} effectTriggerProp='Initial value' />
<EffectConsumer useEffectSubscribe={useEffectSubscribe} />
</div>
);
};
Fetch example
import React, {useEffect} from 'react';
import {useCustomEffect} from 'use-custom-effect';
const Fetcher = ({runFetchEffect}) => {
const handleFetch = () => {
runFetchEffect('START');
fetch("https://api.com/data")
.then(res => res.json())
.then(
(result) => {
runFetchEffect('SUCCESS', result);
},
(error) => {
runFetchEffect('ERROR', error);
}
);
};
return (
<div>
<button onClick={handleFetch}>Fetch</button>
</div>
);
};
const Consumer = ({useFetchEffect}) => {
const [fetchCounter, setFetchCounter] = useState(0);
const [{data, loading, error}, setState] = useState({
data: null,
error: null,
loading: false,
});
useFetchEffect((status, response) => {
if (status === 'START') {
setFetchCounter(fetchCount + 1);
setState({
data: null,
error: null,
loading: true,
});
return;
}
if (status === 'SUCCESS') {
setState({
data: response,
error: null,
loading: false,
});
return;
}
if (status === 'ERROR') {
setState({
data: null,
error: response,
loading: false,
});
return;
}
}, [fetchCounter, setState, setFetchCounter]);
return (
<div>
{loading && <p>Loading...</p>}
{data && <p>{JSON.stringify(data)}</p>}
{error && <p>Error: {error}</p>}
<p>Fetch counter: {fetchCounter}</p>
</div>
);
};
const App = () => {
const [useFetchEffect, run] = useCustomEffect();
return (
<div>
<Fetcher runFetchEffect={run} />
<Consumer useFetchEffect={useFetchEffect} />
</div>
);
};
Typescript
Typescript implementation just includes specifying custom effect callback type:
const [useEffectSubscribe, run] = useCustomEffect<(id: number, status: string) => void>();
-
Reducing props propagation.
You can resolve custom effect logic in the upper scope, and just delegate custom effect subscribe hook to the effect consumers. (There is no need to propagate props which take part into effect).
-
Controlling effect execution moment.
Via
useCustomHook
API, therun
function is at your disposal that executes all effect callbacks synchronously. -
Using custom effects as a composition unit.
You can use created custom effect hook to build more complex effects / UI behaviors.
MIT © radospavlicevic
This hook is created using create-react-hook.