How to pass Information from a functional child component to a parent React?

Asked

Viewed 2,567 times

2

I’m developing an application with React with Hooks and functional components, and I came across the following logic: I need to screen render the functional components, both with Forms arrays inside the main component, instead of sending the information to my API within each component I found it more practical for the child components to pass the arrays to the parent component and send it once, so I thought I’d pass as a props a function that arrow the array into a state of the parent component, but every time I try to access this function from the child component of an error.

Parent component:

function Config(){

    const [registerData, setRegisterData] = useState([])
    const [deleteData, setDeleteData] = useState(null)

    function setRegister(dados){
        setRegisterData(dados)
    }

    function setDelete(dados){
        setDeleteData(dados)
    }

    console.log(registerData, deleteData)

    return(
        <div>
            <Register data={setRegister} />
            <br />
            <Delete data={setDelete} />
        </div>
    )
}
export default Config;

Child component:

function Register({props}){

    const [usuario, setUsuario] = useState('')
    const [telefone, setTelefone] = useState('')
    const [unidade, setUnidade] = useState('')
    const [departamento, setDepartamento] = useState('')
    const [cargo, setCargo] = useState('')


    const form = {usuario: usuario, telefone: telefone, unidade: unidade, departamento: departamento, cargo: cargo}

    props.setRegister(form);

    return(
        <div className="app">

            <center>
            <input type="text" onChange={(e) => setUsuario(e.target.value)} className="form-input" placeholder="Usuário" />
            <br />
            <br />
            <input type="text" onChange={(e) => setTelefone(e.target.value)} className="form-input" placeholder="Telefone" />
            <br />
            <br />
            <select>
                <option onChange={(e) => setUnidade(e.target.value)}>Selecione uma unidade</option>
                <option value="UB">UB</option>
                <option value="UG">UG</option>
                <option value="UM">UM</option>
                <option value="UP">UP</option>
                <option value="UV">UV</option>
                <option value="UL">UL</option>
            </select>
            <br />
            <br />
            <input type="text" onChange={(e) => setDepartamento(e.target.value)} className="form-input" placeholder="Departamento" />
            <br />
            <br />
            <input type="text" onChange={(e) => setCargo(e.target.value)} className="form-input" placeholder="Cargo" />
            <br /><br />
            <br /><br />
            <button className="btn btn-lg btn-dark">Cadastrar</button>
            </center>

        </div>
    )
} 

export default Register; 

The mistake that happens:

TypeError: Cannot read property 'setRegister' of undefined
  • When I hit my eye, I see two errors in your code (I don’t know if you have more). 1) Register({props}) will receive a props with the name props (that is to say, props.props); 2) setRegister is not the name of the props, but yes data (which is a bad name, tidy this up to make it easier to read and understand what it means)

  • The problem here has nothing to do with React. It is the functioning of the Javascript breakdown.

  • Actually, this edition of props I did to conduct a test. So assuming my component is "Register({setRegister})" and in the parent component I pass this way : <Register setRegister={setRegister} />, as I would access this function within the child?

  • How so @Luizfelipe?

1 answer

3


First of all, it is worth remembering that JSX is nothing more than a syntactic sugar for Javascript. In this way, everything can still be represented as functions.

So when you do:

<Register data={setRegister} />

You’re actually invoking the method React.createElement. Thus:

React.createElement(
  Register,
  {
    data: setRegister
  }
);

The first argument being the component you want to create, the second the properties you want him to pass and the third the children (children). As in the example in question, the component has no children, this parameter has been omitted. For more information, see documentation.

Keeping this in mind, it is important to also be aware that properties (what we pass in the second argument to createElement) can be accessed by the first parameter of functional components. Thus:

function Register(props) {
  console.log(props);
}

Thus, assuming the previous example, the above example would print on the browser console { data: setRegister }. Behold:

function setRegister() {
  // Do stuff.
}

function Register(props) {
  console.log(props);
  
  return null;
}

ReactDOM.render(
  // Mesmo que:
  // <Register data={setData} />
  React.createElement(
    Register,
    {
      data: setRegister
    }
  ),
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

So when you disrupt the properties, like this:

function Register({ props }) {
  // ...
}

You’re only trying to get the property props of the objects props which is passed to the first argument of Register by React. It makes no sense, since you didn’t even pass props for the component Register:

<Register data={setData} />

Note that we passed data, but not props.

Therefore, to access the function setData, do:

// Note que não estamos mais desestruturando.
function Register(props) {
  console.log(props.data); // Irá imprimir a sua função.

  // Para chamar a função, faça:
  props.data();

  // ...
}

But understand that name data does not make sense. It does not even help to identify what the property does. Therefore, I think it would be a little more "pleasant" rename it to something like setRegister.

Then you’ll do:

function Register(props) {
  // Chamando...
  props.setRegister();

  // ...
}

<Register setRegister={setRegister} />

Suggested reading

  • Puts understood, is that as I always used the props only with JSX I thought it was the same principle and always had to fragment them, thanks very much.

  • It happens. Some say that just use and go understand as you use enough. I personally agree, although not ideal. Understanding a little bit of how things work "behind the scenes" - like JSX, in this case, can be quite useful sometimes. :-)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.