I am creating a "presentation" component with multiple sections, each rendered dynamically.
In the parent component which houses all the different children, I want the "next button" disabled for each part until a certain condition has been met. The button lives in the parent component.
This component does not pass the property:
Child one example:
export function ChildOne() {
const [condition, setCondition] = useState(false);
return (
<div>
<button onClick={() => setCondition(true)}>
hello world
</button>
</div>
);
}
Parent:
import ChildOne, condition from "../child-one"
export default function Parent() {
return(
<div className="childRenderer">
{page == 1 && (
<ChildOne />
)}
</div>
<button isDisabled={condition}>Next</button>
);
}
I'm not sure how to pass the condition property from the child component so that I can use it in the parent component. In addition, is this methodology an anti-pattern? Can I conditionally make the button in the parent disabled based on values from the child component in another way?
Thank you.
try this way
child:
export function ChildOne({setCondition}) {
return (
<div>
<button onClick={() => setCondition(true)}>
hello world
</button>
</div>
);
}
Parent:
import {ChildOne} from "../child-one"
export default function Parent() {
const [condition, setCondition] = useState(false);
return(
<div className="childRenderer">
{page == 1 && (
<ChildOne setCondition={setCondition} />
)}
</div>
<button isDisabled={condition}>Next</button>
);
}
You should use a state in parent component to control disabled for steps. It can use when you have other pages.
export default function Parent() {
const [condition, setCondition] = useState({});
const changeCondition = (val) => {
setCondition({...condition, [page]: val})
}
return(
<div className="childRenderer">
{page == 1 && (
<ChildOne changeCondition={} />
)}
</div>
<button isDisabled={!condition[page]}>Next</button>
);
}
export function ChildOne({changeCondition}) {
return (
<div>
<button onClick={() => {changeCondition(true)}}>
hello world
</button>
</div>
);
}
You could pass the onClick fucntion as a props param.
Child
export function ChildOne({onClick}) {
return (
<div>
<button onClick={onClick}>
hello world
</button>
</div>
);
}
Parent
import ChildOne, condition from "../child-one"
export default function Parent() {
const [condition, setCondition] = useState(false);
return(
<div className="childRenderer">
{page == 1 && (
<ChildOne onClick={() => setCondition(true)} />
)}
</div>
<button isDisabled={condition}>Next</button>
);
}
in your Parent component try this :
import ChildOne, condition from "../child-one"
export default function Parent() {
const [condition, setCondition] = useState(false);
const handleClick = () => setCondition(true)
return(
<div className="childRenderer">
{page == 1 && (
<ChildOne handleClick={handleClick} />
)}
</div>
<button isDisabled={condition}>Next</button>
);
}
and in use children :
export function ChildOne({handleClick}) {
return (
<div>
<button onClick={handleClick}>
hello world
</button>
</div>
);
}
Related
I have a component I want to update parent state from child component clicked. But there is if else condition due to this I'm not able to update state in parent component.
I have two boxes with if else condition & I want to update state in both boxes but its update in only one box. How to solve this?
Working sandbox code
Screenshot:-
App.js Code:-
import React, { useState } from "react";
import "./styles.css";
import Halfbox from "./Halfbox";
export default function App(props) {
const [name, setName] = useState(false);
if (props.type == "left-section") {
return (
<div className="App">
<b class="state"> {name ? <>right update</> : <>right not update</>}</b>
<Halfbox setName={setName} />
</div>
);
} else if (props.type == "right-section") {
return (
<div className="App">
<b class="state"> {name ? <>left update</> : <>left not update</>}</b>
<p>This is left box</p>
</div>
);
}
}
Halfbox.js Code:-
export default function Halfbox(props) {
const handleClick = (e) => {
props.setName(true);
};
return (
<div>
<h1>Halfbox</h1>
<button onClick={handleClick}>Click</button>
</div>
);
}
Thanks for your efforts!
It seems that there are 2 instance of App, therefore each has its own name state. And the event is only updating the state for its parent App but not the other one.
To have both boxes updated, perhaps a very basic approach could be try moving them down as child components of the same App, so that they can share the name state passed down from it.
Example: (forked live on: codesandbox)
export default function App(props) {
const [name, setName] = useState(false);
return (
<>
<Section
type="left-section"
title="Left Section"
name={name}
setName={setName}
/>
<Section
type="right-section"
title="Right Section"
name={name}
setName={setName}
/>
</>
);
}
export const Section = (props) => {
if (props.type === "left-section") {
return (
<div className="App">
<b className="state">
{props.name ? <>right update</> : <>right not update</>}
</b>
<Halfbox setName={props.setName} />
</div>
);
} else if (props.type === "right-section") {
return (
<div className="App">
<b className="state">
{props.name ? <>left update</> : <>left not update</>}
</b>
<p>This is left box</p>
</div>
);
}
};
This is a very noob question but I've been trying all day do implement this. Please help me out.
Sorry for the length, just tried to put out the whole thing I am struggling with
I am trying to build custom buttons and to do so, I created a component so I can create as many buttons that I want. For that I declared a state and passed down some information as props, which is as follows:
import React, {useState} from 'react'
import Button from '../components/Button'
function CustomButton() {
const [clicked, setClicked] = useState(false)
return (
<div className='CustomButton'>
<Navbar />
<Button setClicked={setClicked} name="Button One" clicked={clicked}/>
<Button setClicked={setClicked} name="Button Two" clicked={clicked}/>
<Button setClicked={setClicked} name="Button Three" clicked={clicked}/>
</div>
)
}
export default CustomButton
As you can see, we passed the state and name of that button down. To render this Buttons, following component has been created:
import React from 'react'
import Modal from './Modal/Modal'
function Button({setClicked, name, clicked}) {
return (
<div>
<button onClick={() => {setClicked(true)}}>{name}</button>
{clicked && <Modal closeModal={setClicked} name={`You Clicked ${name}`} />}
</div>
)
}
export default Button
And lastly, when once a button is clicked, we want to perform some action. That action is to pop the Modal on a screen. And to do so, we created a Modal and passed down few props. Code for the same is as follows:
import React from 'react'
function Modal({closeModal, name}) {
return (
<div className='modal'>
<div className='modalContainer'>
<p>{name}</p>
<div>
<button onClick={() => {closeModal(false)}}>×</button>
</div>
</div>
</div>
)
}
export default Modal
The expected result is for a Modal to pop with "You clicked button One", supposing we clicked one something similar to this.
The actual result is that all three Modals pop up one above the other when any of the three buttons are passed. The result:
I realize that I am passing the states wrong way. When any of the button is clicked all three get set to true. I simply don't realize how. Don't they create a method for each one?
Also, can you guys please teach me a better/understandable way to write clicked logic. Like maybe
if(clicked){
<Modal closeModal={setClicked} name={`You Clicked ${name}`} />
}
Because you bind all three buttons with one state, You need a state as array, with items equal to the number of buttons.
const [clicked, setClicked] = useState([false, false, false])
return (
<div className='CustomButton'>
<Navbar />
{
clicked.map((button, i) => {
return <Button setClicked={setClicked} name="Button Three" clicked={clicked[i]} index={i}/>
})
}
</div>
)
Then in the button component.
function Button({setClicked, name, clicked, index}) {
return (
<div>
<button onClick={() => {setClicked(prev => prev.map((item, i) => {
return i === index ? true : item
}))}}>{name}</button>
{clicked && <Modal closeModal={setClicked} name={`You Clicked ${name}`} />}
</div>
)
}
And the modal component.
function Modal({ closeModal, name, index }) {
return (
<div className="modal">
<div className="modalContainer">
<p>{name}</p>
<div>
<button
onClick={() => {
closeModal((prev) =>
prev.map((item, i) => {
return i === index ? false : item;
})
);
}}
>
×
</button>
</div>
</div>
</div>
);
}
You can find a working example on this link.
https://codesandbox.io/s/old-wood-zgjno9
You can implement multiple modals like this:
import { useState } from "react";
export default function App() {
const [showModal1, setShowModal1] = useState(false);
const [showModal2, setShowModal2] = useState(false);
return (
<div className="App">
<button onClick={(e) => setShowModal1(true)}>Button 1</button>
<button onClick={(e) => setShowModal2(true)}>Button 2</button>
{showModal1 && (
<Modal text="Modal 1" onClose={(e) => setShowModal1(false)} />
)}
{showModal2 && (
<Modal text="Modal 2" onClose={(e) => setShowModal2(false)} />
)}
</div>
);
}
const Modal = ({ text, onClose }) => {
return (
<div>
{text}
<button onClick={onClose}>Close</button>
</div>
);
};
Working example
I am new to learning react and am stuck with this doubt. I have a simple button and on click of that button I want to add some text (or any other html) element. The console log statement is getting executed but the div tag is not getting rednered. This is my following code.
function App() {
const executeMe = () => {
console.log("executed")
return(
<div> Clicked here</div>
)
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
</div>
</LocalizationProvider>
);
}
export default App;
I know that I am missing out something which may be very simple. Please help me fix this. Thanks
Your looking at React wrongly, it doesn't work this way. You can do this instead.
import { useState } from "react";
function App() {
const [clicked, setClicked] = useState(false);
const [lines, setLines] = useState([]);
const executeMe = () => setClicked(!clicked);
const onAddLine= () => setLines(lines.concat("New line (Could be unique)"));
return (
<div className="App">
Hello world
{/* METHOD A */}
{!clicked && <button onClick={executeMe }>Click me</button>}
{clicked && <div>Clicked here</div>}
<br />
{/* METHOD B */}
<button onClick={executeMe}>{clicked ? "Clicked here" : "Click me"}</button>
<br />
{/* ADDITIONAL FUN STUFF WITH SEPERATE BUTTON */}
<button onClick={onAddLine}>Add new line</button>
<br />
{lines.map((line, x) => {
return(
<div key = {x}>{x+1} : {line}</div>
);
})}
</div>
);
};
export default App;
You can render that div by using state instead and reset it on the next click.
function App() {
const [showDiv, setShowDiv] = useState(false);
const executeMe = () => {
console.log("executed");
setShowDiv(!showDiv);
};
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{showDiv && <div> Clicked here</div>} {/* render div once showDiv state is true */}
</div>
</LocalizationProvider>
);
}
export default App;
You should add a state value to check when the button has been pressed.
Here is more information about how to use useState hook.
function App() {
const [isButtonPressed, setIsButtonPressed] = useState(false);
const executeMe = () => {
console.log("executed");
setIsButtonPressed(true);
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{isButtonPressed && <div>Clicked here</div>}
</div>
</LocalizationProvider>
);
}
export default App;
There are many ways to achieve it.
First React is just JavaScript, most JS code will work within the component.
But some dev might find it not so React which is weird for me :)
So here are the two examples that you might try:
function App() {
const [list, setList] = React.useState([])
const handleAddLine = () => {
const lists = document.getElementById('lists')
const li = document.createElement('li')
li.textContent = 'hey'
lists.append(li)
}
const handleAddLineReactish = () => {
setList(prevList => {
return prevList.concat(<li>hey</li>)
})
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleAddLine}>Add</button>
<ul id='lists'></ul>
<button onClick={handleAddLineReactish}>Add Reactish</button>
<ul>
{list.length > 0 && list.map((l, i) => {
return (
<li key={i}>{l}</li>
)
})}
</ul>
</div>
);
}
sandbox URL: https://codesandbox.io/s/funny-sun-7f4epn?file=/src/App.js
For something like this we use a react hook called "useState".
In "useState" we store a something and on the basis of that we do stuff like to show, hide and more.
See the image
you can write that html code in another component and import it into the current file you can make useState to check the value is 'visible' with type 'true/false' to check the state when the button is click.
code example
import React, { useState } from "react";
function App() {
const [showText, setShowText] = useState(false);
const executeMe = () => {
console.log("executed")
setShowText(true);
}
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<div className="App">
Hello world
<Button onClick={executeMe}> click me</Button>
{showText ? <Text /> : null}
</div>
</LocalizationProvider>
);
}
const Text = () => <div>You clicked the button!</div>;
export default App;
So I want when I press the button in the Button Component everything in the 'li section' disappears as well as in the ImageComponent but it not working I would like to know what my mistake is. ButtonComponent is rendered somewhere else.
App Component/Parent
function App({ hideButton }) {
return (
<div className="App">
<ImageComponent hideButton={hideButton} />
</div>
);
}
// ButtonComponent
function ButtonComponent() {
const [hideButton, setHideButton] = React.useState(false)
function handleClick() {
setHideButton(true)
}
return (
{
!hideButton && (
<li>
<img className="image"src="./icons/>
<Button onClick={handleClick} variant="outlined" className="button__rightpage" >Hide</Button>
<caption className="text"> Hide</caption>
</li >
)
}
)
}
// ImageComponent
const ImageComponent = ({ hideButton }) => {
return (
<div>
{
!hideButton && (
<div>
<img src='icons/icon.png' />
<caption>Image </caption>
</div>
)
}
</div>
)
}
you need to lift up the state to the most parent Component be accessible to the ButtonCommponent and the ImageComponent. in this Case App Component. however, if the ButtonComponent is rendered out of the hierarchy under the App Component tree, you should use the context API.
create a context and share the state on it and it will be accessible on the application level.
//#1. create context.
export const HiddenContext = React.createContext(false);
//#2. create the provider and share the state with it.
function HiddenProvider({ children }) {
const [hideButton, setHideButton] = React.useState(false);
function handleClick() {
setHideButton(true);
}
return (
<HiddenContext.Provider value={{ hideButton, handleClick }}>
{children}
</HiddenContext.Provider>
);
}
//#3. render the provider component to the most top parent component
export default function App() {
const { hideButton } = React.useContext(HiddenContext);
return (
<HiddenProvider>
<div className="App">
<ImageComponent hideButton={hideButton} />
<OtherComponentRenderTheButton />
</div>
</HiddenProvider>
);
}
// other component that render the button
function OtherComponentRenderTheButton() {
return <ButtonComponent />;
}
//ButtonComponent
function ButtonComponent() {
const { hideButton, handleClick } = React.useContext(HiddenContext);
return (
<React.Fragment>
{!hideButton && (
<li>
<img className="image" src="./icons" alt="" />
<Button
onClick={handleClick}
variant="outlined"
className="button__rightpage"
>
Hide
</Button>
<caption className="text"> Hide</caption>
</li>
)}
</React.Fragment>
);
}
// ImageComponent
const ImageComponent = () => {
const { hideButton } = React.useContext(HiddenContext);
return (
<div>
{!hideButton && (
<React.Fragment>
<img src="icons/icon.png" alt="" />
<caption>Image </caption>
</React.Fragment>
)}
</div>
);
};
working demo
I want to render my data after button click. I use the condition rendering in my component and create a boolean variable in state object. After button clicked variable is changed and (as I expected) my data was renderered. But nothing happens. I know that this is a basic mistake.
class SortingMyArray extends React.Component {
constructor(props) {
super(props)
this.state = {
addcomments: addcomments,
isClicked : false
}
// this.sortBy = this.sortBy.bind(this)
}
sortBy() {
let sortedComments = [...this.state.addcomments].sort((a,b) => new Date(b.date) - new Date(a.date));
this.setState({
addcomments: sortedComments,
isClicked : true
})
console.log(this.state.isClicked)
}
render(){
return(
<div>
<div>
<button
onClick={() => this.sortBy() }>AdditionalCommentaries
</button>
</div>
</div>
)
if (this.state.isClicked){
return(
<div>
<div>
<AddComments addcomments = {this.state.addcomments} />
</div>
</div>
)
}
}
}
export default SortingMyArray;
You need to restructure your render method since part of code is unreachable, also you don't need to use IF sentence, you can use logical operator && to ask if isClicked is true to return AddComments component.
You need to install eslinter in your code editor, this can you help to detect this type
errors or others
RENDER METHOD:
render() {
//You can destructuring object, in this case your state is the object
const { isClicked, addcomments } = this.state;
return (
<div>
<div>
<button onClick={() => this.sortBy()}>AdditionalCommentaries</button>
</div>
{isClicked && (
<div>
<AddComments addcomments={addcomments} />
</div>
)}
</div>
);
}
You should not have more than one return inside render method. Instead try this:
Note: There is no if-else statement in JSX but we use the one bellow
render(){
return(
<div>
<div>
<button
onClick={() => this.sortBy() }>AdditionalCommentaries
</button>
</div>
</div>
{
this.state.isClicked
&&
<div>
<div>
<AddComments addcomments = {this.state.addcomments} />
</div>
</div>
}
)
}
This part of your code is unreachable by the program since it is placed after return. You should not have two returns.
if (this.state.isClicked){
return (
<div>
<div>
<AddComments
addcomments={this.state.addcomments}
/>
</div>
</div>
)
}
Also, your conditional statement is not valid JSX. Your render method should look something like this
render() {
return (
<div>
<div>
<button onClick={() => this.sortBy()}>
AdditionalCommentaries
</button>
</div>
{this.state.isClicked && (
<div>
<div>
<AddComments
addcomment={this.state.addcomments}
/>
</div>
</div>
)}
</div>
)
}