Hadi Ranjbar
Hadi Ranjbar

Reputation: 1802

Change react hook state from parent component

I have a hook component like this:

import React, { useState} from "react";

const MyComponent = props => {
  const [value, setValue] = useState(0);
  const cleanValue = () => {
    setValue(0);
  };

  return (<span><button onClick={()=>setValue(1)}/>{value}<span>)
}

I want to reset value from the parent component. How I can call clean value from parent component? the parent component is a stateful component.

Upvotes: 18

Views: 26117

Answers (3)

Aprillion
Aprillion

Reputation: 22324

From the React documentation about Fully uncontrolled component with a key:

In order to reset the value ..., we can use the special React attribute called key. When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here.

In this case, we can use a simple counter to indicate the need for a new instance of MyComponent after pressing the Reset button:

const { useState } = React;

const Parent = () => {
  const [instanceKey, setInstanceKey] = useState(0)
  const handleReset = () => setInstanceKey(i => i + 1)
  return (
   <div>
    <MyComponent key={instanceKey} />
    <button onClick={handleReset} type="button">Reset</button>
   </div>
  )
}

const MyComponent = () => {
  const [value, setValue] = useState(0)
  return (
    <span>
      <button type="button" onClick={()=>setValue(v => v + 1)}>{value}</button>
    </span>
  )
};

ReactDOM.render(<Parent />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"/>

Upvotes: 12

Shubham Khatri
Shubham Khatri

Reputation: 281686

If the parent has to control the child state then probably the state must reside in the parent component itself. However you can still update child state from parent using ref and exposing a reset method in child. You can make use of useImperativeHandle hook to allow the child to only expose specific properties to the parent

const { useState, forwardRef, useRef, useImperativeHandle} = React;


const Parent = () => {
  const ref = useRef(null);
  return (
     <div>
      <MyComponent ref={ref} />
      <button onClick={() => {ref.current.cleanValue()}} type="button">Reset</button>
     </div>
  )
}

const MyComponent = forwardRef((props, ref) => {
  const [value, setValue] = useState(0);
  
   const cleanValue = () => {
    setValue(0);
  };

  useImperativeHandle(ref, () => {
     return {
      cleanValue: cleanValue
     }
  });

  return (<span><button type="button" onClick={()=>setValue(1)}>Increment</button>{value}</span>)
});
ReactDOM.render(<Parent />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"/>

Upvotes: 33

Matthieu Libeer
Matthieu Libeer

Reputation: 2365

You can't / shouldn't. Using hooks instead of stateful class components doesn't change the fact that if you want the parent to own the state, you need to declare the state in the parent.

It should look something like this, depending on when you want to reset the value (here I used another button):

const MyButton = (props) = (
  // Whatever your button does, e.g. styling
  <span>
    <button {...props} />
  <span>
)


const Parent = props => {
  const [value, setValue] = useState(0);
  const cleanValue = () => setValue(0);
  return (
    <div>
      <MyButton onClick={() => setValue(1)}>
        {value}
      </MyButton>
      <button onClick={cleanValue}>
        Reset
      </button>
    </div>
  )
}

Upvotes: 5

Related Questions