Share a Hook from one component to another

Asked

Viewed 467 times

0

My question is the following, I have a component in React called Navbar.jsx and would like the title no Navbar changed as soon as another component was opened.

For example, when you open the customer registration screen, change the title to "Customer Registration".

I used the useState HOOK to create the title.

But when opening another component I wanted to change the state of the title to another title once it was rendered, so I try to call with useEffect, but it does not work and gives an error.

"Attempted import error: 'setTitulo' is not Exported from '.. /Components/Navbar' (Imported as 'Navbar')."

Navbar.jsx

import React from 'react';
import { useState } from 'react'
import { Nav, Navbar, NavDropdown } from 'react-bootstrap'

const NavBar = (props) => {

const [titulo, setTitulo] = useState("Controle Diário")

return (
<Navbar className="shadow-lg mb-5 bg-secondary " variant="light">
    <Navbar.Brand href="/">
        <img
            src={logo}
            
            height="40"
            className="d-inline-flex align-top"
            alt="Logo"
        />
    </Navbar.Brand>
    <Nav className="mr-auto">
        <Nav.Link href="#">Controle Diário</Nav.Link>
        <NavDropdown title="Cadastro" id="basic-nav-dropdown">
            <NavDropdown.Item href="/clientes">Clientes</NavDropdown.Item>
            <NavDropdown.Item href="#">Motorista</NavDropdown.Item>
            <NavDropdown.Item href="#">Notas Fiscais</NavDropdown.Item>
            <NavDropdown.Divider />
            <NavDropdown.Item href="#">Outros</NavDropdown.Item>
        </NavDropdown>
    </Nav>
    <h4 className="mr-auto font-weight-bold">{titulo}</h4>
</Navbar>
)}

export default NavBar 

Mainclient.jsx

import React from 'react';
import { useState, useEffect } from 'react'
import * as NavBar from '../components/NavBar'

const MainClientes = (props) => {

// Esta e a linha que esta gerando o erro

useEffect(NavBar.setTitulo("Cadastro de Clientes"),[])

....

2 answers

1

Give a check on the response of this post What is "Prop Drilling"? for a more complete explanation, there are also some examples of the three alternatives cited below.

There are three alternatives:

  • Redux, but it is used in specific cases and when really needed, own experience, do not use Redux if you do not need really.

  • Context API and Render props, React itself offers tools to handle this.

  • Thanks, I took a look at the topic, of the options you have, I will initially try Render props, I found enough content on. I’ll understand better and apply it to see how it looks.

1

Talk face beauty? Look there are many ways to do this. Have a similar question on community in English I’ll link here I think you can help.

That way it doesn’t work basically because you’re trying to access a variable within the scope of another function.

One thing that is cool to note is that it is not very cool to keep state out of the components or store, this can cause DOM upgrade problems. I have some suggestions for a solution:

  1. Keep the state in the component above has a very cool technique of studying known as HOC which basically consists of maintaining the logical part in the parent components.

So imagine having two child components want them to share a state for that is just keep the state in the parent this way:

const rootElement = document.getElementById("root");

function ChildA(prop) {
  return (
    <section>
      <button 
        onClick={
          () => prop.alterar('alterado atraves do A')
        }>
        Alterar atravez do A
      </button>
      Valor no A: { prop.valor }
    </section>
  )
}

function ChildB(prop) {
  return (
    <section>
      <button 
        onClick={
          ()=> prop.alterar('alterado atraves do B')
        }>
        Alterar atravez do B
      </button>
      Valor no B: { prop.valor }
    </section>
  )
}

function App() {
  const [state, setState] = React.useState('inicial');
  
  return (
    <div>
      <ChildA valor={state} alterar={setState} />
      <ChildB valor={state} alterar={setState} />
    </div>
   )
}

ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

  1. Keep it in a store like Redux so you have the flexibility to access and change it from anywhere, the code is a bit complex but if you are creating a more robust application is a good way.

const rootElement = document.getElementById('root');
const ALTERAR = 'ALTERAR';

// ESSA SERIA SUA STORE
const reducer = (state = 'inicial', action) => {
  switch (action.type) {
    
    case ALTERAR:
      return action.valor;
      
    default:
      return state;
  }
};

const store = Redux.createStore(reducer);

const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;

// AQUI VOCE MAPEIA OS ESTADOS QUE O COMPONENTE IRA USAR PARA EVITAR RENDERIZAÇÕES DESNECESSARIAS
const mapStateToProps = (state) => {
  return { valor: state };
};

// AQUI VOCE MAPEIA OS REDUCERS QUE DESEJA USAR COMO PROP
const mapDispatchToProps = (dispatch) => {
  return {
    alterar: (valor) => {
      dispatch({ type: ALTERAR, valor })
    }
  }
};

function ChildA(prop) {
  return (
    <section>
      <button 
        onClick={
          () => prop.alterar('alterado atraves do A')
        }>
        Alterar atravez do A
      </button>
      Valor no A: {prop.valor}
    </section>
  )
}

const ChildAConectado = connect(mapStateToProps, mapDispatchToProps)(ChildA);

function ChildB(prop) {
  return (
    <section>
      <button 
        onClick={
          ()=> prop.alterar('alterado atraves do B')
        }>
        Alterar atravez do B
      </button>
      Valor no B: {prop.valor}
    </section>
  )
}

const ChildBConectado = connect(mapStateToProps, mapDispatchToProps)(ChildB);


function App() {
  return (
    <Provider store={store}>
      <main>
        <ChildAConectado />
        <ChildBConectado />
      </main>
    </Provider>
  )
}

ReactDOM.render(<App />, rootElement);
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.7/react-redux.min.js"></script>

<div id="root"></div>

  1. You can use a specific lib for this they are not very famous for not being officers but fulfill what they promise below some of them:

  • Thank you for the content in your reply, I will study calmly these possible outputs to decide which to use.

Browser other questions tagged

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