4

useLocal: the useState hook for a properly-synced state

 3 years ago
source link: https://dev.to/theluk/uselocal-the-usestate-hook-for-a-properly-synced-state-32kp
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Cover image for useLocal: the useState hook for a properly-synced state

useLocal: the useState hook for a properly-synced state

Jul 11

・2 min read

As you might know, the React hook useState takes one argument, which will initialize its internal state to that given value. When React 16 with Hooks got released, I found it a little bit confusing, but it perfectly makes sense.

No matter what, there are still situations, where you need to update the state based on the incoming props. Usually that is done using a useEffect hook, where you listen on the incoming prop to change, and then update your local state.

This is a great way of handling it, because you, as the owner of the component can perfectly control, if the parent prop change is actually what you want. It could even break your component if the parent decides to update a prop during a critical state of your component.

But there are also situations, where not much can happen. There are simple scenarios where you basically want to hold a local version and not propagate it up the tree until a certain condition happen. During that time, you still want to allow the parent controlling component to update the local value, if that is what it wants.

Here is an example how to allow the parent controlling component set (and update, if necessary) the from and to values. It can happen that for example for whatever reason, there is another component, that can set a date range, for that, we would want that from and to can be updated.

const RangeDatepicker = ({ value: { from, to }, onChange }) => {
   const [from, setFrom] = useLocal(from)
   const [to, setTo] = useLocal(to)
   const update = () => {
    if (from && to) {
      onChange({ from, to });
    }
   }

   useEffect(update, [from, to])

   return <MyCalendarRangePicker from={from} to={to} onChangeFrom={setFrom} onChangeTo={setTo} />
}
Enter fullscreen modeExit fullscreen mode

the easiest implementation of such a hook (in Typscript) looks like this

import { useState, useEffect, Dispatch, SetStateAction } from 'react';

export function useLocal<S>( remote: S | (() => S), ): [S, Dispatch<SetStateAction<S>>] { const [data, setData] = useState(remote); useEffect(() => setData(remote), [remote]); return [data, setData]; }

One further improvement would be, to pass in some conditional function that checks, if it is allowed to update the local state.

import { useState, useEffect, Dispatch, useRef } from 'react';

type CheckFunc<S> = (nextRemoteValue: S, currentLocalValue: S) => boolean;

export function useLocal<S>( remote: S, condition?: CheckFunc<S>, ): [S, Dispatch<S>] { const [data, setData] = useState(remote);

const canUpdateRef = useRef<undefined | ((nextVal: S) => boolean)>(); canUpdateRef.current = condition ? (next: S) => condition(next, data) : undefined;

useEffect(() => { if (canUpdateRef.current && !canUpdateRef.current(remote)) { return; } setData(remote); }, [remote]); return [data, setData]; }

You can visit the gist here

https://gist.github.com/theluk/13b7a17455b599699b7d34775cbf8273


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK