DEV Community

Cover image for React.js ~The principle of the hook~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

React.js ~The principle of the hook~

Use only one useEffect per page

  • Bad
const [foo, setFoo] = useState("foo");

useEffect(() => {
  setFoo("bar");
});

useEffect(() => {
  setFoo("baz");
});
Enter fullscreen mode Exit fullscreen mode

It is not clear which state would be updated.

  • Good
const [foo, setFoo] = useState("foo");

const onClickBar = () => setFoo("bar");

const onClickBaz = () => setFoo("baz");

Enter fullscreen mode Exit fullscreen mode

Instead, you should do away with the useEffect to prevent multiple updates.

In many cases, useEffect is not required. In reality, you use only one useEffect per page.

Events that occur in the browser are as follows:

  • Page navigation, initial render, Path sifting, and so on.
  • User events: click, tap.
  • EventListner event: Connecting or disconnecting from the network.
  • Event from server: WebSocket, real-time update from Firebase.

User events are not only required in useEffect. While most applications require page navigation or user events.
As a result, in many cases, useEffect requires page navigation.

Add a comment on the dependencies array in useEffect

  • Bad: Load function
const [isLoaded, setIsLoaded] = useState<boolean>(false);
const [res, setRes] = useState();

const load = useCallback(async () => {
    try {
        if (isLoaded) {
            return;
        }
        const fooApiRes = await FooApi();
        setRes(fooApiRes);
    } finally {
        setIsLoaded(true);
    }
}, [isLoaded]);

useEffect(() => {
    load();
}, [load]);

Enter fullscreen mode Exit fullscreen mode

If the props is a boolean, you should divide the component into different components

  • Bad: A component includes both create and update
const DialogContents: React.FC<{isAdd: boolean}> = ({
    isAdd: boolean,
}) => {
    ...
    const onSubmit = useCallback(async () => {
        if (isAdd) {
            await FooRegisterApi();
            return;
        }
        await FooUpdateApi();
    }, []);

    return (
        <>
            <form onSubmit={onSubmit}>
                <label>Name</label>
                <input value={name} onChange=>{onChangeName}/>
                <label>ID</label>
                <input disabled={!isAdd} value={id} onChange=>{onChangeId}/>
                {isAdd &&
                    <label>Email</label>
                    <input value={email} onChange=>{onChangeEmail}/>
                    <label>PhoneNumber</label>
                    <input value={phoneNumber} onChange=>{onChangePhoneNumber}/>
                }
            </form>
        </>
    )
}
Enter fullscreen mode Exit fullscreen mode

This codebase increases conditional statements as the app grows.

  • Good: Divide the component into two components, such as a create component and an update component.
const RegisterDialogContents: React.FC = () => {
    ...
    const onSubmit = useCallback(async () => {
        await FooRegisterApi();
    }, []);

    return (
        <>
            <form onSubmit={onSubmit}>
                <label>Name</label>
                <input value={name} onChange=>{onChangeName}/>
                <label>ID</label>
                <input value={id} onChange=>{onChangeId}/>
                <label>Email</label>
                <input value={email} onChange=>{onChangeEmail}/>
                <label>PhoneNumber</label>
                <input value={phoneNumber} onChange=>{onChangePhoneNumber}/>
            </form>
        </>
    )
}

const UpdateDialogContents: React.FC = () => {
    ...
    const onSubmit = useCallback(async () => {
        await FooUpdateApi();
    }, []);

    return (
        <>
            <form onSubmit={onSubmit}>
                <label>Name</label>
                <input value={name} onChange=>{onChangeName}/>
                <label>ID</label>
                <input disabled={true} value={id} onChange=>{onChangeId}/>
            </form>
        </>
    )
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)