1

I know this could be a noob question but I'm learning React for a few months and now I'm stucked with this problem. I got this code over here:

import React, { useCallback, useEffect, useRef, useState } from 'react'
import ReactTags from 'react-tag-autocomplete'

const TagsHandler = ({ tagPlaceholder, suggestions }) => {
  const [tags, setTags] = useState([])
  const reactTags = useRef()

  const onDelete = useCallback(
    (tagIndex) => {
      setTags(tags.filter((_, i) => i !== tagIndex))
    },
    [tags]
  )

  const onAddition = useCallback(
    (newTag) => {
      setTags([...tags, newTag])
    },
    [tags]
  )

  useEffect(() => {
    suggestions.map((suggestion) => {
      suggestion.disabled = tags.some((tag) => tag.id === suggestion.id)
    })
  }, [tags])

  return (
    <ReactTags
      ref={reactTags}
      tags={tags}
      suggestions={suggestions}
      onDelete={onDelete}
      onAddition={onAddition}
      placeholderText={tagPlaceholder}
    />
  )
}

export default TagsHandler

Which implements a tag list inside my parent component. This parent component has a bool value which enables a save button. I should enable this button whenever a user adds or removes a tag to the list. My question is: how can I handle this bool from the child component? I've read about Redux but I'd like to avoid using it. I was thinking about a SetState function or a callback but I can't figure out the syntax. Any help would be really appreciated, thanks :)

  • you can have the `state` in parent component, and pass the `state`, `setter` reference to the child and then set using setter passed from parent in child .... – KcH Sep 29 '22 at 06:41
  • That's wierd. You already know how to pass a function from parent to a child. Why not do the same thing in a high level of components. – PeterT Sep 29 '22 at 06:46
  • @KcH passing `setter` gives you far less flexibility then passing custom callback function every time you use the component – deaponn Sep 29 '22 at 06:48
  • @deaponn, yeah but that's okay for a simple e.g. – KcH Sep 29 '22 at 06:50
  • This question is a duplicate of https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs – deaponn Sep 29 '22 at 07:19
  • Does this answer your question? [How to pass data from child component to its parent in ReactJS?](https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs) – deaponn Sep 29 '22 at 07:20

3 Answers3

2

You can simply create a function in your parent component: toggleButton, and pass the function to your child component.

function Parent = (props) => {
    const [isToggle, setIsToggle] = useState(false);

    const toggleButton = () => {
          setIsToggle(!isToggle)
    }

    return <Child toggled={isToggle} toggle={toggleButton} />
}
Roy Christo
  • 354
  • 2
  • 13
  • 1
    This is not a toggle function as it only sets your boolean to `true` instead of toggling it. – deaponn Sep 29 '22 at 06:45
  • yeah, it's not toggle – KcH Sep 29 '22 at 06:51
  • @RoyChristo, we didn't mean to change the naming , you have to do state set as `setIsToggle( prev => !prev)` so it checks previous state and inverts it (which would be toggle) ... hope it makes sense – KcH Sep 29 '22 at 07:10
  • HaHa... my bad again. updated – Roy Christo Sep 29 '22 at 07:11
  • Thanks for your answer : I already have a structure like this in my parent component: `const [isTouched, setTouched] = useState(false)` Shouldn't I call the toggle prop anywhere in my child component? – Gian Marco Pane Sep 29 '22 at 07:13
  • If you pass it to your child. Yes – Roy Christo Sep 29 '22 at 07:17
  • Ok, so I'd like to call it inside my UseEffect so everytime my tags array is updated I can enable the save button. Let's suppose I've got something like this: `const TagsHandler = ({ tagPlaceholder, suggestions, setBool })` How should I modify my UseEffect function? – Gian Marco Pane Sep 29 '22 at 07:27
  • some thing like this `useEffect(() => { if(isArrayUpdated){ setBool() } })` – Roy Christo Sep 29 '22 at 07:46
  • I've modified my child like this: `useEffect(()=>{setBool()}`. Inside my parent I got `const toggleButton=()=>{setTouched(true)}` and then `return – Gian Marco Pane Sep 29 '22 at 08:41
  • `useEffect(() => { suggestions.map((suggestion) => { suggestion.disabled = tags.some((tag) => tag.id === suggestion.id) }); setBool(); }, [tags])` – Roy Christo Sep 29 '22 at 12:14
0

So the general approach is as follows:
In the Parent.jsx:

const [childrenActive, setChildrenActive] = useState(false)

// later in the render function
<Children setIsActive={(newActive) => setChildrenActive(newActive)} />

In the Children.jsx:

const Children = ({ setIsActive }) => {
    return <button onClick={() => setIsActive(true)}>Click me</button>
}

So, as you have guessed, we pass a callback function. I would avoid passing setState directly because it makes your component less flexible.

deaponn
  • 837
  • 2
  • 12
  • I guess it should be ` setChildrenActive(!newActive)} />` ... – KcH Sep 29 '22 at 06:51
  • @KcH no, as it would make input reversed. This is a callback function and when you pass `true` to it, it would set negated, `false`, to the `setState` – deaponn Sep 29 '22 at 07:07
  • That's what buddy you missed `!newActive` which I added – KcH Sep 29 '22 at 07:07
  • And then when OP calls `setIsActive(true)` from children, `childrenActive` will be set to `false` in parent because it got negated. This is not the desired behavior as we wanted to set this boolean `true` in the first place. – deaponn Sep 29 '22 at 07:09
  • I didn't miss that, it's just setting directly what needs to be set. If you wanted to make a toggle mutation, you would do `setChildrenActive(current => !current)` in the parent component. – deaponn Sep 29 '22 at 07:11
  • hmm, so it shouldn't be called "toggle" tbh – KcH Sep 29 '22 at 07:15
  • @KcH I didn't use word toggle once in my answer, nor did OP use it in his question. – deaponn Sep 29 '22 at 07:17
  • haha my bad ... seeing the answer voted above and the comments I have thought it ... nvm :) – KcH Sep 29 '22 at 07:19
0

In the parent component, the function that is responsible for changing that bool variable, you pass as a prop to the child component. At the child component you get that props and you can update if you want.

Thien
  • 51
  • 1
  • 5