How do I change the state of the parent component from the child component in Reactjs? - 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);
}

Related

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>
</>
}

React; rendering components from an array depending on what tab im in

What I want my code to do
I need to make tabs that display different components depends on the state
My issue
I don't know how to render the correct component using a conditional depending on what tab I'm in with react
What my code is doing so far
I have an array of all my components in the const allTabs
depending on what button i click the state of tabNum changes
import React, {useState} from "react";
import Tabcomp1 from './../components/tabcomp1';
import Tabcomp2 from './../components/tabcomp2';
const allTabs = [Tabcomp1, Tabcomp2];
const Pagetwo = () =>{
const[tabNum, setTabNum] = useState("0");
const changeTab = (e) =>{
e.preventDefault();
if (tabNum === "0") {
setTabNum("1");
console.log(tabNum);
}
else {
setTabNum("0");
console.log(tabNum);
}
}
return(
<div>
<h1>you are now on page 2</h1>
{/* tab1 */}
<button id={0} onClick={changeTab}>tab 1</button>
{/* tab2 */}
<button id={1} onclick={changeTab}>tab 2</button>
<br />
{/* display the correct component here */}
</div>
)
}
export default Pagetwo;
in you button event handler you can set index as
onClick={() => setTabNum(0 // tab index here)}
and below you button you can render it like
{allTabs[tabNum]}

React Hooks Calling GET Request On Modal Popup

Thanks in advance for any help you can provide. I am trying to create a Modal is react and call a get request to load details of a task.
I have most of it working (I think), but essentially what I have done is createa custom Modal Hook that toggles two modals.
The second of the two modals is meant to open a task and render the task details in a form for editing but I am unable to get it working.
Here is the useModal hook:
import { useState } from "react";
const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
const [secondModalIsShowing, secondModalSetIsShowing] = useState(false);
function toggle() {
setIsShowing(!isShowing);
}
function secondToggle() {
secondModalSetIsShowing(!secondModalIsShowing);
console.log("clicked");
}
return {
isShowing,
toggle,
secondModalIsShowing,
secondToggle,
};
};
export default useModal;
I then call the function for the secondToggle which fires the code below to render the modal. Now as you may see I have to comment out the section where it calls getTask() with match.params.id, as well as the component that is then meant to be rendered in the modal.
If I don't do that I get an error message with the following " Line 23:5: Expected an assignment or function call and instead saw an expression no-unused-expressions"
import React, { Fragment, useEffect, useState } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import TaskItem from "../tasks/task-item/TaskItem";
import { getTask } from "../../actions/task";
import ReactDOM from "react-dom";
import "./Modal.styles.scss";
import "../dashboard/Dashboard.styles.scss";
import Task from "../task/Task";
import TaskEdit from "../task/TaskEdit";
const TaskModal = ({
getTask,
task: { task, loading },
match,
secondModalIsShowing,
hide,
}) => {
const [displayEdit, toggleDisplayEdit] = useState(false);
useEffect(() => {
getTask();
// match.params.id;
}, [getTask]);
return secondModalIsShowing
? ReactDOM.createPortal(
<React.Fragment>
<button
type="submit"
value="toggle"
onClick={() => toggleDisplayEdit(!displayEdit)}
>
Show/Edit
</button>
{(displayEdit && <TaskItem task={task} />) || (
<div>{/* <TaskEdit /> */}</div>
)}
<div className="modal-overlay" />
<div
className="modal-wrapper"
aria-modal
aria-hidden
tabIndex={-1}
role="dialog"
>
<div className="modal">
<div className="modal-header">
Add New Task
<button
type="button"
className="modal-header__button"
data-dismiss="modal"
aria-label="Close"
onClick={hide}
>
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
</React.Fragment>,
document.body
)
: null;
};
Now if I render this EditTask component outside the modal as a normal component it works correctly. I can also get the modal to render when it's not trying to display the EditTask component.
As a result, I think it's related to the Route path and passing the response to the TaskModal component? When I click the modal to open I cant get it to render the URL with the task ID and therefore I cant render the details of the task in the modal.
<Route path="/taskedit/:id" component={TaskModal} />
For context, I think this guide comes close to solving my issue (https://blog.logrocket.com/building-a-modal-module-for-react-with-react-router/) but I am not familiar with working with class-based components and when I try and convert to functional-based components I'm running into even more issues.
Thanks in advance for any insight you can provide as I keep trying to work through this.
Paul
The first issue I am seeing is you have to pass the task id to TaskModal component
<Route path="/taskedit/:id"
render={(props) => <TaskModal {...props} />}>
</Route>
This will make the task id available as property in TaskModal.
Then in the TaskModal, fetch like below
let taskid = prop.match.params.id;

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

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} />
</>
}

How to trigger a function from one component to another component in React.js?

I'am creating React.js Weather project. Currently working on toggle switch which converts celcius to fahrenheit. The celcius count is created in one component whereas toggle button is created in another component. When the toggle button is clicked it must trigger the count and display it. It works fine when both are created in one component, but, I want to trigger the function from another component. How could I do it? Below is the code for reference
CelToFahr.js (Here the count is displayed)
import React, { Component } from 'react'
import CountUp from 'react-countup';
class CeltoFahr extends Component {
state = {
celOn: true
}
render() {
return (
<React.Fragment>
{/* Code for celcius to farenheit */}
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CountUp
start={!this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
end={this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
duration={2}
>
{({ countUpRef, start}) => (
<h1 ref={countUpRef}></h1>
)}
</CountUp>
</div>
</div>
</div>
</div>
{/*End of Code for celcius to farenheit */}
</React.Fragment>
)
}
}
export default CeltoFahr
CelToFahrBtn (Here the toggle button is created)
import React, { Component } from 'react'
import CelToFahr from './CeltoFahr'
class CelToFahrBtn extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render = (props) => {
return (
<div className="button" style={{display: 'inline-block'}}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={this.switchCel} className="CelSwitchWrap">
<div className={"CelSwitch" + (this.state.celOn ? "" : " transition")}>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CelToFahrBtn
Here when I click on switchCel it must trigger the celcius to fahrenheit value and vice-versa. How to do it? Any suggestions highly appreciated. Thanks in advance
I would have the celToFahr be the parent component of the celToFahrBtn and then pass the function you want to invoke via props
<CellToFahrBtn callback={yourfunction}/>
What else could you do is having a common parent for these to components where you would again do the execution via props and callbacks
The 3rd option would be having a global state which would carry the function like Redux or Reacts own Context. There again you would get the desired function via props and you would execute it whenever you like. This is the best option if your components are completely separated in both the UI and in source hierarchically, but I don't think this is the case in this case.
https://reactjs.org/docs/context.html
These are pretty much all the options you have
To achieve this you'd need to lift your state up and then pass the state and handlers to the needed components as props.
CeltoFahr & CelToFahrBtn would then become stateless components and would rely on the props that are passed down from TemperatureController
class TemperatureController extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render () {
return (
<React.Fragment>
<CeltoFahr celOn={this.state.celOn} switchCel={this.state.switchCel} />
<CelToFahrBtn celOn={this.state.celOn} switchCel={this.state.switchCel}/>
</React.Fragment>
)
}
}
It's probably better explained on the React Docs https://reactjs.org/docs/lifting-state-up.html
See this more simplified example:
import React, {useState} from 'react';
const Display = ({}) => {
const [count, setCount] = useState(0);
return <div>
<span>{count}</span>
<Button countUp={() => setCount(count +1)}></Button>
</div>
}
const Button = ({countUp}) => {
return <button>Count up</button>
}
It's always possible, to just pass down functions from parent components. See Extracting Components for more information.
It's also pretty well described in the "Thinking in React" guidline. Specifically Part 4 and Part 5.
In React you should always try to keep components as dumb as possible. I always start with a functional component instead of a class component (read here why you should).
So therefore I'd turn the button into a function:
import React from 'react';
import CelToFahr from './CeltoFahr';
function CelToFahrBtn(props) {
return (
<div className="button" style={{ display: 'inline-block' }}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={() => props.switchCel()} className="CelSwitchWrap">
<div
className={'CelSwitch' + (props.celOn ? '' : ' transition')}
>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default CelToFahrBtn;
And you should put the logic in the parent component:
import React, { Component } from 'react';
import CountUp from 'react-countup';
import CelToFahrBtn from './CelToFahrBtn';
class CeltoFahr extends Component {
state = {
celOn: true
};
switchCel = () => {
this.setState({ celOn: !this.state.celOn });
};
render() {
return (
<>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CelToFahrBtn switchCel={this.switchCel} celOn={celOn} />
</div>
</div>
</div>
</div>
</>
);
}
}

Resources