Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store initial prop state in function component?

I need to pass some props to a third-party drawing library, but I need to pass only the initial value of the prop. I've made a wrapper component which captures the initial props in state, and then passes them to the third-party component.

This works, but since setZoom and setCenter aren't used, it feels like an anti-pattern:

function Wrapper({ center, zoom }) {
  const [initialZoom, setInitialZoom] = useState(zoom);
  const [initialCenter, setInitialCenter] = useState(center);

  return <ThirdParty zoom={initialZoom} center={initialCenter} />
}

I tried useMemo but eslint also warned about missing dependencies:

React Hook useMemo has a missing dependency: 'zoom'. Either include it or remove the dependency array.eslintreact-hooks/exhaustive-deps

function Wrapper({ center, zoom }) {
  const initialZoom = useMemo(() => zoom, []); // eslint-disable-line react-hooks/exhaustive-deps
  const initialCenter = useMemo(() => center, []); // eslint-disable-line react-hooks/exhaustive-deps

  return <ThirdParty zoom={initialZoom} center={initialCenter} />
}

Is there an idiomatic way to do this? Or is it so non-standard that just ignoring the eslint warnings on the useMemo example is the best option?

like image 769
Laura Murphy-Clarkin Avatar asked Oct 28 '25 05:10

Laura Murphy-Clarkin


1 Answers

This works, but since setZoom and setCenter aren't used, it feels like an anti-pattern:

function Wrapper({ center, zoom }) {
  const [initialZoom, setInitialZoom] = useState(zoom);
  const [initialCenter, setInitialCenter] = useState(center);

  return <ThirdParty zoom={initialZoom} center={initialCenter} />
}

This isn't so much anti-pattern as much as it is just unused declarations. You don't need to destructure the state updater function. Just set the initial value and don't ever update it.

function Wrapper({ center, zoom }) {
  const [initial] = useState({ center, zoom });

  return <ThirdParty zoom={initial.zoom} center={initial.center} />
}

I tried useMemo but eslint also warned about missing dependencies:

React Hook useMemo has a missing dependency: 'zoom'. Either include it or remove the dependency array.eslintreact-hooks/exhaustive-deps

function Wrapper({ center, zoom }) {
  const initialZoom = useMemo(() => zoom, []); // eslint-disable-line react-hooks/exhaustive-deps
  const initialCenter = useMemo(() => center, []); // eslint-disable-line react-hooks/exhaustive-deps

  return <ThirdParty zoom={initialZoom} center={initialCenter} />
}

This is also a valid use case, using an empty dependency array to run the hook once on component mount, but as you see, the react hook linting rules will complain about a possible missing dependency.

Other alternatives include:

  • Using a React ref to hold the initial values:

    function Wrapper({ center, zoom }) {
      const initialRef = useRef({ center, zoom });
    
      return <ThirdParty zoom={initialRef.zoom} center={initialRef.center} />
    }
    

Instead of a wrapper component you may want a Higher Order Component to just memoize the initial props value.

Example:

const withMemoizedInitialProps = Component => props => {
  const initialPropsRef = useRef(props);
  return <Component {...initialPropsRef.current} />
};

...

const DecoratedThirdParty = withMemoizedInitialProps(ThirdParty);

...

<DecoratedThirdParty zoom={zoom} center={center} />

Edit how-to-store-initial-prop-state-in-function-component

like image 142
Drew Reese Avatar answered Oct 29 '25 21:10

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!