-1

I have a parent and a child component, child component has a button, which I'd like to disable it after the first click. This answer works for me in child component. However the function executed on click now exists in parent component, how could I pass the attribute down to the child component? I tried the following and it didn't work.

Parent:

const Home = () => {
  let btnRef = useRef();
  const handleBtnClick = () => {
    if (btnRef.current) {
        btnRef.current.setAttribute("disabled", "disabled");
    }
  }
  
  return (
    <>
      <Card btnRef={btnRef} handleBtnClick={handleBtnClick} />
    </>
  )
}

Child:

const Card = ({btnRef, handleBtnClick}) => {
  return (
    <div>
      <button ref={btnRef} onClick={handleBtnClick}>Click me</button>
    </div>
  )
}
one-hand-octopus
  • 2,229
  • 1
  • 17
  • 51

3 Answers3

3

In general, refs should be used only as a last resort in React. React is declarative by nature, so instead of the parent "making" the child disabled (which is what you are doing with the ref) it should just "say" that the child should be disabled (example below):

const Home = () => {
  const [isButtonDisabled, setIsButtonDisabled] = useState(false)
  const handleButtonClick = () => {
    setIsButtonDisabled(true)
  }
  
  return (
    <>
      <Card isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
    </>
  )
}


const Card = ({isDisabled, onButtonClick}) => {
  return (
    <div>
      <button disabled={isDisabled} onClick={onButtonClick}>Click me</button>
    </div>
  )
}
Zeke Hernandez
  • 1,226
  • 11
  • 14
  • glad to help, if you have an imperative coding background like I did, it takes a little bit getting used to the declarative paradigm, but once it clicks you really start cooking with gas. – Zeke Hernandez Sep 16 '20 at 21:20
0

Actually it works if you fix the typo in prop of Card component. Just rename hadnlBtnClick to handleBtnClick

Boussadjra Brahim
  • 82,684
  • 19
  • 144
  • 164
Omer Gurarslan
  • 979
  • 11
  • 15
0

You don't need to mention each prop/attribute by name as you can use javascript Object Destructuring here.

const Home = () => {
  const [isButtonDisabled, setIsButtonDisabled] = useState(false)
  const handleButtonClick = () => {
    setIsButtonDisabled(true)
  }
  
  return (
    <>
      <Card isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
    </>
  )
}


const Card = (props) => {
  return (
    <div>
      <button {...props}>Click me</button>
    </div>
  )
}

You can also select a few props and use them differently in the child components. for example, see the text prop below.

const Home = () => {
  const [isButtonDisabled, setIsButtonDisabled] = useState(false)
  const handleButtonClick = () => {
    setIsButtonDisabled(true)
  }
  
  return (
    <>
      <Card text="I'm a Card" isDisabled={isButtonDisabled} onButtonClick={handleButtonClick} />
    </>
  )
}


const Card = ({text, ...restProps}) => {
  return (
    <div>
      <button {...restProps}>{text}</button>
    </div>
  )
}
Vikas Gautam
  • 1,793
  • 22
  • 21