@witivio_teamspro/use-reducer
v3.1.2
Published
React useMagicReducer hook
Downloads
20
Keywords
Readme
React useMagicReducer custom hook
Advantages compared to original useReducer hook
- Immutable state : you can't update state manually, you have to use dispatch function.
- No need to create types for reducer methods.
- You can choose to render or not component when set state (render by default).
- Access state and reducer functions of your component from top components.
- The function setState allows to update state partially.
- No need to create handlers, dispatch method can be called with a closure.
Example of usage
import React, {ReactElement} from "react";
import {MagicReducerObject, MagicReducerRef, useMagicReducer, useMagicReducerRef} from "@witivio_teamspro/use-reducer";
export type State = {
isOpen: boolean,
message: string,
}
export type Props = {
externalRef: MagicReducerExternalRef<typeof reducer>,
}
export type DialogRef = Props["externalRef"];
export const Dialog = (props: Props): ReactElement | null => {
const [state, dispatch] = useMagicReducer(reducer, initialState, props.externalRef);
const style: CSSProperties = {
display: state.isOpen ? "flex" : "none",
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
backgroundColor: "white",
width: "200px",
height: "200px",
flexDirection: "column",
color: "black"
}
return (
<div style={style}>
<button onClick={dispatch("close")}>Close X</button>
{state.message}
</div>
)
}
export const initialState: State = {
isOpen: false,
message: "",
}
export const reducer = {
open: ({setState}, [event]: [React.SyntheticEvent | undefined], message: string) => {
event?.stopPropagation();
setState({isOpen: true, message});
},
close: ({setState}) => {
setState({isOpen: false});
}
} satisfies MagicReducerObject<State>;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const TopComponent = () => {
const dialogRef = useMagicReducerRef(Dialog);
return (
<div>
<Dialog externalRef={dialogRef}/>
<button onClick={dialogRef.dispatch("open", "Hello world")}>
Open dialog
</button>
</div>
)
}
How to use props inside reducer functions ?
You just need to create a function for the reducer and pass props as argument, instead of having a simple object.
Here is an example:
export const Dialog = (props: Props): ReactElement | null => {
const [state, dispatch] = useMagicReducer(reducer(props), initialState, props.externalRef);
//...
}
export const reducer = (props: Props) => ({
//...
logProps: () => {
console.log(props)
}
}) satisfies MagicReducerObject<State>;
How to type correctly dispatch method in a pure function ?
Use the type MagicDispatch<typeof reducer>
to type correctly the dispatch function.
Here is an example:
import {MagicDispatch} from "@witivio_teamspro/use-reducer";
const myFunction = (dispatch: MagicDispatch<typeof reducer>) => {
dispatch({type: "logProps"});
}
How to type correctly magic reducer reference in a pure function ?
Use the type MagicReducerRef<typeof Component>
to type correctly the reference.
Here is an example:
import {MagicReducerRef} from "@witivio_teamspro/use-reducer";
const myFunction = (dialogRef: MagicReducerRef<typeof Dialog>) => {
dialogRef.dispatch("open")();
}