I’ve a Parent-Child component structure. In parent, I’ve a function that calls a web service and take few seconds to complete. From parent, I’m passing this function as a prop to the child. Child component displays buttons with an onClick
tied to parent’s function. How can I disable the buttons in child after click, till the parent’s callback function finishes execution, and then re-enable them?
e.g. in code below, doOperation
is such a function with a setTimeout()
to simulate a web service call delay:
Parent Component:
export default function App() {
const [val, setVal] = useState(0);
const doOperation = (qty) => {
setTimeout(() => {
setVal((prev) => prev + qty);
}, 5000);
};
return (
<div className="App">
<input placeholder={val} />
<div style={{ display: "flex" }}>
<ChildButtons qty={1} doOperation={doOperation} />
</div>
</div>
);
}
Child Component:
const ChildButtons = ({ qty, doOperation }) => {
const [disabled, setDisabled] = useState(false);
return (
<div>
<button
onClick={() => {
// How can I disable the button prior to call and enable after it.
setDisabled(true);
doOperation(qty);
setDisabled(false);
}}
disabled={disabled}
>
{" "}
+ {qty}
</button>
<button
onClick={() => {
// How can I disable the button prior to call and enable after it.
setDisabled(true);
doOperation(-1 * qty);
setDisabled(false);
}}
disabled={disabled}
>
{" "}
- {qty}
</button>
</div>
);
};
https://codesandbox.io/s/quizzical-easley-7oyeyk
Update:
Although the sample code above has only two pairs of button, there potentially could be any number of buttons. What I have is a scrollable list with two button per list item, so technically, there can be any number of buttons on the display in pairs of two.
2
Answers
You have to lift the state to the parent component:
And use it inside the child:
You have to "promisify" the callback function so that you can
await
it (at least that’s the simplest way – you could also do this with.then
, or, more verbosely, in callback style by passing callbacks to the parent function that it will perform before and after the main function):Parent Component:
(so the parent component hasn’t actually really changed, I’ve just converted the
setTimeout
calls to promises to make it easier to "wait for them" in the child component).Child Component:
(It’s not clear what the second child button is supposed to do here. You can do the same as in the first button, although in the original code you don’t appear to be trying to do that, so I’ve left it as is here. Looking at your response to the other answer, if you want the second button disabled independently of the first you will of course need 2 separate state variables in the child component, one for the
disabled
state of each button.)