QWIK state management syntax for React with a custom hook. Alternative to setState.



This content originally appeared on DEV Community and was authored by Sourav

Utilizing Javascript proxy this custom changes the default way of setting state in React which is a function that requires a function.
By using this hook simply assigning value to state will result same as setState. It’s really a wrapper around useState.

Here is usProxyState simple 20 lines of code.

https://github.com/Sourav9063/watchtogether/blob/master/src/helper/hooks/useProxyState.js

    import { useState } from "react";
    export const useProxyState = (initialState = {}) => {
      if (typeof initialState != "object") {
        initialState = { value: initialState };
      }
      const [state, setState] = useState(initialState);
      state.setState = setState;
      const handler = {
        set(_, prop, value) {
          if (value !== state[prop]) {
            setState((state) => {
              return { ...state, [prop]: value };
            });
          }
          return Reflect.set(...arguments);
        },
      };
      const stateProxy = new Proxy(state, handler);
      return stateProxy;
    };

Notes

  • For Object type state, direct assignment will work i.e. state.count. Any other type state you can access and modify via state.value

  • You can get the default setState in state.setState()

    const state1 = useProxyState({ count: 1 });
    const state2 = useProxyState(1);
    //...
    state1.count = 100;
    state2.value = 200;

Comparisons

useProxyState

    "use client";
    import { useProxyState } from "@/helper/hooks/useProxyState";
    import styles from "../page.module.css";
    export default function Personal() {
      const state1 = useProxyState({ count: 1 });// object
      const state2 = useProxyState(state1.count * 2);// not object

      state2.value = state1.count * 2; //no need for useEffect. And cannot be changed else where.
      return (
        <>
          <main className={styles.main}>
            <div className={styles["cards"]}>
              <button
                onClick={() => {
                  state1.count++; //simple assignment will update the state
                }}
              >{state1.count}
              </button>
              <button
                onClick={() => {
                  state2.value++;// for values other than object, use value.
                }}
              >{state2.value}
              </button>
            </div>
          </main>
        </>
      );
    }

Default useState

    "use client";
    import styles from "../page.module.css";
    import { useEffect, useState } from "react";

    export default function Personal() {
      const [state3, setState3] = useState({
        count: 1,
      });
      const [state4, setState4] = useState(state3.count * 2);
      useEffect(() => {
        setState4(state3.count * 2);
        return () => {};
      }, [state3.count]);

      return (
        <>
          <main className={styles.main}>
            <div className={styles["cards"]}>
              <button
                onClick={() => {
                  setState3((state) => ({ ...state, count: state.count + 1 }));
                }}
              >
                useState {state3.count}
              </button>
              <button
                onClick={() => {
                  setState4((state) => {
                    return state + 1;
                  });
                }}
              >
                useState {state4}
              </button>
            </div>
          </main>
        </>
      );
    }

Demo Source

GITHUB: sourav9063
WEBSITE: https://sourav9063.github.io/
LINKDIN: sourav-ahmed


This content originally appeared on DEV Community and was authored by Sourav