labilouser
labilouser

Reputation: 337

Toggle visibility of two components from buttons inside of them in React

I have this structure

component 1

import React, { useState } from 'react'

export default function Component1() {
    return (
        <div>
            <button onClick={handleChange}></button>
        </div>
    )
}

component 2

import React, { useState } from 'react'

export default function Component2() {
    return (
        <div>
            <button onClick={handleChange}></button>
        </div>
    )
}

and the parent

import React from 'react'

export default function Parent() {
    return (
        <div>
            <Component1 />
            <Component2 />
        </div>
    )
}

The question is, how can I toggle visibility between the two, without having a button in the parent. Just the buttons inside each component. - The Component1 should be visible by default and when you press the button in Component1 it will hide it and show Component2 and vice-versa.

I've tried using useState hook on the Component1 button, but I'm not sure how to export the state and add it to the parent component.

    const [showMini, setShowMini] = useState(false);

    const handleChange = () => {
      setShowMini(true);
    }

Is this possible? or it's possible just with a button in the parent that control the two? Thanks

Upvotes: 2

Views: 2359

Answers (5)

Sakshi
Sakshi

Reputation: 1548

Try this:

import React from 'react'

export default function Parent() {
    const[show,setShow]=useState(false);
    const handleChange=()=>{
        setShow(!show);
    }
    return (
        <div>
            {show ? <Component2 handleChange={handleChange}/> : <Component1 handleChange={handleChange}/>}
        </div>
    )
}

and inside Component1 have this:

import React, { useState } from 'react'

export default function Component1({handleChange}) {
    return (
        <div>
            <button onClick={handleChange}></button>
        </div>
    )
}

Similarly do it for Component2

Upvotes: 3

mscandan
mscandan

Reputation: 47

Try this. You can send information from child to parent with functions passed as a prop.

Parent Component:

const Parent = () => {
  const [show, setShow] = useState(true);
  const toggleVisibility = () => {
    setShow(!show);
  };
  return (
    <div>
      {show ? (
        <Child1 toggle={toggleVisibility}></Child1>
      ) : (
        <Child2 toggle={toggleVisibility}></Child2>
      )}
    </div>
  );
};

Child 1

const Child1 = (props) => {
  const { toggle } = props;
  return (
    <div style={{ width: '100px', height: '100px' }}>
      <button onClick={toggle}>Child 1's button</button>
    </div>
  );
};

Child 2

const Child2 = (props) => {
  const { toggle } = props;
  return (
    <div style={{ width: '100px', height: '100px' }}>
      <button onClick={toggle}>Child 2's button</button>
    </div>
  );
};

Upvotes: 0

tmdesigned
tmdesigned

Reputation: 2254

Your parent component should keep track of the state:

import React, {useState} from 'react'

export default function Parent() {
    const [showChild, setShowChild] = useState(1);

    const showNextChild = () => {
        setShowChild( showChild === 1 ? 2 : 1 ); // set to 2 if already 1, else to 1
    }

    return (
        <div>
            { showChild === 1 && <Component1 handleChange={showNextChild} /> }
            { showChild === 2 && <Component2 handleChange={showNextChild} /> }
        </div>
    )
}

A few notes:

  1. Your components are identical, so the duplication is unnecessary, but I assume the example is just contrived.

  2. This assumes toggling 2 components back and forth. If you have more than 2 components you are "looping" through, you can instead increment the previous showChild state and then reset it to 0 if higher than the # of components you have.

  3. The syntax you see, showChild === 1 && <Component1 ... uses the behavior of the && operator which actually returns the 2nd item it is evaluating if both are true. In other words, const isTrue = foo && bar; sets isTrue to bar, not true as you might expect. (You know, however, that bar is "truthy" in this case, so isTrue still works in future if statements and such.) The component is always truthy, so the effect is that the component is returned if the first part is true, otherwise it is not. It's a good trick for conditionally showing components.

Upvotes: 0

kingisaac95
kingisaac95

Reputation: 66

You can manage the state in the parent and pass down a handler to the children

import React, { useState } from 'react'

const [currentView, setCurrentView] = useState('component1')

const changeCurrentView = (view) => setCurrentView(view)

const renderViews = () => {
  switch(currentView) {
    case 'component1':
      return <Component1 changeCurrentView={changeCurrentView} />
    case 'component2':
      return <Component2 changeCurrentView={changeCurrentView} />
    default:
      return <Component1 changeCurrentView={changeCurrentView} />
  }
}

export default function Parent() {
  return (
    <div>
      {renderViews()}
    </div>
  )
}

Other components

import React from 'react'

export default function Component1({ changeCurrentView }) {
  return (
    <div>
      <button onClick={() => changeCurrentView('component1')}></button>
    </div>
  )
}


export default function Component2({ changeCurrentView }) {
  return (
    <div>
      <button onClick={() => changeCurrentView('component2')}></button>
    </div>
  )
}

Upvotes: 0

ZealousWeb
ZealousWeb

Reputation: 1751

You can do with state value and pass handleChange function ad props in the child component and in click on the button in child component call handleChange method under parent component and show hide based on state value.

import React from 'react'
    const [showChild, setshowChild] = useState(false);
    
    const handleChange = () => {
        setshowChild(!showChild);
    }
    
    export default function Parent() {
        return (
            <div>
                {showChild ? <Component2 handleChange = {handleChange}/> : <Component1 handleChange= {handleChange} />}
            </div>
        )
    }

Upvotes: 0

Related Questions