How to toggle class of a div element by clicking on a button that is inside another functional component (another file)? - reactjs

I want to toggle class of container (file 2) by an onClick on the button that is inside another component file.
The button has already an onClick function and I want to make it so it calls on two functions. Two toggle functions for the button and two class toggles for the container.
Hope it makes sense.
Here is my code so far:
Button component (File 1)
import React, {useState} from "react";
import "./Sort.scss";
const Sort = () => {
const [toggleSortIcon, toggleSortIconSet] = useState(false);
return (
<div className="tools">
<button
onClick={() => toggleSortIconSet(!toggleSortIcon)}
className={`sort ${toggleSortIcon ? "horizontal" : "vertical"}`}>
</button>
</div>
);
}
export default Sort;
Div container component that I want to change the class of (File 2)
import React, {useState} from "react";
import "./WordContainer.scss";
import UseAnimations from "react-useanimations";
const WordContainer = ({title, definition, example}) => {
const [toggleSize, toggleSizeState] = useState(false);
return (
<div className={`container ${toggleSize ? "big" : "small"}`}>
<div className="content">
<h2>{title}</h2>
<p>{definition}</p>
<h3>Example</h3>
<p>{example}</p>
</div>
<img onClick={() => toggleSizeState(!toggleSize)} src="./resize.svg" alt="resize" className="resize"/>
<div className="bookmark">
<UseAnimations
animationKey="bookmark"
size={26}
/>
</div>
</div>
);
}
export default WordContainer;

You could either have a global state management system (redux, or with custom hooks) that you can use to store the icon size.
Or you could simply provide a callback to your component that stores the icon size in a parent component that then feeds it back to your
Something like this:
const [size, setSize] = useState(/* default value */);
render() {
<>
<Sort onSizeToggle={setSize} />
<WordContainer size={size} />
</>
}

Related

How to pass CSS class names in React JS

I want to change the width of a component whenever I click a button from another component
This is the button in BiCarret:
import { useState } from "react";
import { BiCaretLeft } from "react-icons/bi";
const SideBar = () => {
const [open, setOpen] = useState(true);
return (
<div className="relative">
<BiCaretLeft
className={`${
open ? "w-72" : "w-20"
} bg-red-400 absolute cursor-pointer -right-3 top-5 border rounded-full`}
color="#fff"
size={25}
onClick={setOpen(!true)}
/>
</div>
);
};
export default SideBar;
and this is the component I want to change the width on click
import "./App.css";
import SideBar from "./components/SideBar/SideBar";
function App() {
return (
<div className="app flex">
<aside className="h-screen bg-slate-700"> // change the width here
<SideBar />
</aside>
<main className="flex-1 h-screen"></main>
</div>
);
}
export default App;
You have two simple solutions, either:
Create context
Crete context and store Open value in it, change it on click and in App react to it.
Dom manipulation
In app add ID to element you would like to change and onClick in the other component use document.getElementById(THE_ID).classList.add("new-class-for-increased-width") which gets the DOM element and adds class to it.

component hiding

In react, There is one component A inside there is one component B I have used. There is one more component C, and inside C there is one button which is when clicked it hides the component B from component A.
How can I achieve this functionality
Using only React, you can achieve this by:
Parent/root component to all of these components has a boolean state, let's call it showComponentB. It's initialized to true.
This root component passes down the state showComponentB as a prop to Component A. In Component A, it is used to either show Component B if showComponentB is true or hide if it's false.
Root component passes a function to alter the state of showComponentB into Component C and is called when the button is clicked.
State of showComponentB is updated in root to false and that updated value is passed through to Component A and hides Component B.
You can try something like this. Hope it helps you.
import { useState } from "react";
import "./styles.css";
export default function App() {
const [isVisible, setIsVisible] = useState(true)
return (
<div className="App">
<CompA>
{isVisible && <CompB>
<CompC clickHandler={()=>setIsVisible(false)}/>
</CompB> }
</CompA>
</div>
);
}
export const CompA = (props) => {
return <>
<div style={{backgroundColor:'red', height:'200px',width:'200px'}}>Component A
{props.children}
</div>
</>}
export const CompB = (props) => {
return <>
<div style={{backgroundColor:'blue', height:'150px',width:'150px'}}>Component B
{props.children}
</div>
</>
}
export const CompC = (props) => {
return <>
<div style={{backgroundColor:'green', height:'100px',width:'100px'}}>Component C
<button onClick={props.clickHandler}>hide B</button>
</div>
</>
}

How do I change the state of the parent component from the child component in Reactjs?

I am learning Reactjs and started building simple project along the line. So, I have two components: the parent and child components which I will call component A and B. There is a button in component A (parent component) that will make component B (child component) to popup and will make component A to be unclickable with transparent background (0.3).
Inside component B, I wrote a code that will remove the component once a botton is clicked. This button is right there in component B. So, the problem now is that once I click this button to remove the popup, component A will remain unclickable with transparent background of 0.3. How can I change the state of component A from component B since component B is the child of component A? Is this possible or I need to rewrite the code entirely?
Thank you as you help me.
Component A codes:
import React, { useEffect, useState } from 'react';
import "./home.css";
import {dataFile} from "./data";
import Addbirth from "../components/addbirthday" //this is component B named Addbirth
export default function Home() {
const [showAdd, setShowAdd] = useState(false);
const handleClick = () =>{
setShowAdd(!showAdd)
}
const removeData = (id) =>{
let showRemainingData = datafile.filter((items) => items.id !== id )
setdatefile(showRemainingData)
}
return (
<>
{showAdd && <Addbirth/> }
<div className="container homeContainer">
<div className={showAdd? "homeWrapper unclickable " :"homeWrapper" }>
<h2 className="headerTitle">You have 5 birthdays today</h2>
<button className="btn" onClick={ handleClick} >ADD BITHDAY</button> {/* This
is the button that calls component B and turns component A with transparent
background and unclickable when clicked*/}
component B:
import React, { useState } from 'react';
import "./addbirthday.css";
import "./home.css";
export default function Addbirthday() {
const [closeInput, setCloseInput] = useState(false);
const closeNow = () =>{
setCloseInput(!closeInput)
}
return (
<div className="container">
<div className= { closeInput? "addContainer" :"addWrapper homeWrapper "}>
<i className="fas fa-window-close" onClick={closeNow} ></i> {/* This button will
close conponent B when clicked. */)
<div className= "addbirth">
<label>Name</label>
<input type="text" placeholder="name"/>
<label>Choose Birthdate</label>
<input type="date" />
<label>Relationship</label>
<input type="text" placeholder="Friend" />
</div>
<button className="addBtn" >Add</button>
</div>
</div>
)
}
Thank you as you help me.
I think i understand what you are asking. You just need to pass down the original component to the new Birthday one and have it change back to clickable. In your Return in component A have:
{showAdd && <Addbirth setShowAdd={setShowAdd} /> }
Then in component B import it as props:
export default function Addbirthday({setShowAdd}) {
const [closeInput, setCloseInput] = useState(false);
const closeNow = () =>{
setCloseInput(!closeInput);
setShowAdd(false);
}

Pass state onto {children} React hook

So I have a component that looks like this:
import React, { memo, useState } from "react";
import styles from "./navigation.styles.scss";
const Navigation = ({ children }) => {
const [toggle, toggleState] = useState(false);
return (
<>
<div onClick={() => toggleState(!toggle)}>
<p>Test</p>
</div>
{children}
<style jsx>{styles}</style>
</>
);
};
export default memo(Navigation);
And then I have another component that looks like this:
import React, { memo, useState } from "react";
import styles from "./container.styles.scss";
const Container = ({ children }) => {
const [toggle, toggleState] = useState(false);
return (
<>
<div className={toggle ? "dark-bg" : "dark-bg active"}>
{children}
</div>
<style jsx>{styles}</style>
</>
);
};
export default Container ;
Now, the thing is the {children} of the 1st component is sometimes the 2nd component, and sometimes it's not. Therefore I can't just put the CSS and HTML from the 2ndcomponent into the 1st component - which in turn would fix my problem.
But as you might be able to see, there is an onClick event in the first component. I would like it so that when that is clicked, the state from the click is send to the 2nd component and toggles the className-toggle.
Can this be achieved by doing this, or do I have to set everything up differently ?
And yes, I am quite new to React, so please don't be harsh.
Css
I would look into better methods of applying styling with css. Not sure about your project scope/tools but typically all the css files are imported in the dom root and loaded in there. This avoids creating css files for every component.
Here's 9 ways of implementing css for react.
Passing HTML
In react if you want to render component in another component instead of passing it as a child you should import it as follows.
// replace container path with actual path of Container file
// ex './Container.js'
import Container from 'container_path.js';
Now Rendering the Component is as simple as including it in the html code.
return (
<>
<div className={toggle ? "dark-bg" : "dark-bg active"}>
<Container/>
</div>
</>
);
Here's a Stack Overflow post of users importing components using react + es6 + webpack. More information on importing components is available there.
State management
In react if you have a state that is being accessed by multiple components the standard is to keep the state in the parent component.
This way you can pass the state as a prop to any children components. You can also create a function which updates this state and pass that function as a prop to the children.
ex:
import React, { useState } from "react";
import Container from "./Container.js";
import Navigation from "./Navigation.js"
const Parent = props => {
const [toggle, toggleState] = useState(false);
return (
<div>
<Container toggleState={toggleState} toggle={toggle} />
<Navigation toggleState={toggleState} toggle={toggle} />
</div>
)
}
Before continuing working on your project I would recommend researching functional components vs class components. Here's a helpful article.
Try to wrap second component to function with state from first component as argument.
Wrapper for your second component and using for first component
const putInnerComponent = (stateFromOuterComponent) => <Container toggle={stateFromOuterComponent}/>;
<Navigation children={putInnerComponent}/>
Your first component
import React, { memo, useState } from "react";
import styles from "./navigation.styles.scss";
const Navigation = ({ children }) => {
const [toggle, toggleState] = useState(false);
return (
<>
<div onClick={() => toggleState(!toggle)}>
<p>Test</p>
</div>
{children(toggle)}
<style jsx>{styles}</style>
</>
);
};
export default memo(Navigation);
Your second component
import React, { memo, useState } from "react";
import styles from "./container.styles.scss";
const Container = ({ children, toggle }) => {
//const [toggle, toggleState] = useState(false);
return (
<>
<div className={toggle ? "dark-bg" : "dark-bg active"}>
{children}
</div>
<style jsx>{styles}</style>
</>
);
};
export default Container;

How to use React hooks to determine if sidebar should show?

I have read some introductions on React Hooks and want to make a simple app with a button in the header component, which determines if the main app should show the sidebar. The button sets the variable showSidebar in the header, and I want to read it again within my main component. The code for actually showing the sidebar is stripped out for brevity.
This is index.js:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Header from "./header";
import "./styles.css";
function App() {
const [showSidebar, setShowSidebar] = useState(true);
return (
<div className="App">
<Header />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And this is the header.js:
import React, { useState } from "react";
export default function Header() {
const [showSideBar, setShowSidebar] = useState(true);
const toggleSidebar = () => setShowSidebar(!showSideBar);
return (
<header>
Button in header toggles sidebar:
<button onClick={() => toggleSidebar()}>
Toggle sidebar (state: {showSideBar.toString()})
</button>
</header>
);
}
I am new to React, but do not understand why the state does not update in index.js? I also made a CodeSandbox with the code.
useState is stores local state, for comparison you can think of it similar to setState in a class component (although in reality they aren't exactly equivalent). Therefore, setting setShowSidebar in App won't reflect the same value as that set in Header and vice versa.
It doesn't look like Header needs any form of local state if it's simply changing state of the outer component, you can pass in an event handler and any relevant state Header needs as props instead
index.js
function App() {
const [showSidebar, setShowSidebar] = useState(true);
const toggleSidebar = useCallback(() => setShowSidebar(value => !value));
return (
<div className="App">
<Header onClick={toggleSidebar} showSideBar={showSidebar} />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
header.js
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.onClick}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
);
}
What you're doing wrong is declaring a separate state in Header which you shouldn't do, because it has nothing to do with parent's state. Pass the parent state and a callback to update the parent state as a props to the header. Pass showSidebar as props to the Header component:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Header from "./header";
import "./styles.css";
function App() {
const [showSidebar, setShowSidebar] = useState(true);
return (
<div className="App">
// Pass prop here
<Header
showSidebar={showSidebar}
toggleSidebar={()=>{setShowSidebar(!showSidebar)}}
/>
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
// and then in your Header,
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.toggleSideBar}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
);
}
You want to keep state showSidebar in the parent component (where you need to read it) and pass the functionality to change it to the header component (where you need to change showSidebar)
To do move toggleSidebar to index.js
const toggleSidebar = () => setShowSidebar(!showSideBar);
and pass the function to the Header component like this
<Header toggleSidebar={toggleSidebar} />
now invoke it on clickEvent in Header component like this
<button onClick={() => toggleSidebar()}>
remember to include the prop in your Header component
export default function Header({toggleSidebar}) {
You should have your toggleSidebar function in App.js itself, and pass toggleSidebar function and showSidebar state in Header component as props.
App.js
function App() {
const [showSidebar, setShowSidebar] = useState(true)
const toggleSidebar = () => setShowSidebar(!showSidebar)
return (
<div className="App">
<Header showSideBar={showSidebar} onClick={toggleSidebar} />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
)
}
Header.js
import React from 'react'
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.onClick}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
)
}
Demo

Resources