How to Show div when a Radio Button is Clicked in React - javascript

I have two radios buttons but I want one to show another div if the user clicks yes. I'm new in React.
I have tried this code but the second does not hide the content of the first.
Break down
The user clicks yes,
Another div opens for more info.
The user clicks no,
The div that opened earlier closed.
I know how to toggle in JavaScript but I want to update based on the state.
import React, { Component } from "react";
class Radio extends Component {
constructor(props) {
super(props);
this.state = { clickedYes: false, clickedNo: false };
this.yesHandler = this.yesHandler.bind(this);
this.noHandler = this.noHandler.bind(this);
}
yesHandler() {
this.setState({
clickedYes: !this.state.clickedYes
});
}
noHandler() {
this.setState({
clickedNo: !this.state.clickedNo
});
}
render() {
const radioNo = this.state.clickedNo ?
// Hide div when true
: null;
const radioYes = this.state.clickedYes ? <h1>Yes</h1> : null;
return (
<>
<input
type="radio"
name="release"
id=""
clickedYes={this.state.clickedYes}
onClick={this.yesHandler}
/>
<input
type="radio"
name="release"
clickedNo={this.state.clickedNo}
onClick={this.noHandler}
id=""
/>
{radioYes}
{radioNo}
</>
);
}
}
export default Radio;

Here are two solutions.
With standard React
import React, { Component } from "react";
class Radio extends Component {
constructor(props) {
super(props);
this.state = { status: 0 }; // 0: no show, 1: show yes, 2: show no.
}
radioHandler = (status) => {
this.setState({ status });
};
render() {
const { status } = this.state;
return (
<>
<input type="radio" name="release" checked={status === 1} onClick={(e) => this.radioHandler(1)} />
<input type="radio" name="release" checked={status === 2} onClick={(e) => this.radioHandler(2)} />
{status === 1 && drawYesContent()}
{status === 2 && drawNoContent()}
</>
);
}
}
export default Radio;
With React Hook
import React from "react";
function Radio () {
const [status, setStatus] = React.useState(0) // 0: no show, 1: show yes, 2: show no.
const radioHandler = (status) => {
setStatus(status);
};
return (
<>
<input type="radio" name="release" checked={status === 1} onClick={(e) => radioHandler(1)} />
<input type="radio" name="release" checked={status === 2} onClick={(e) => radioHandler(2)} />
{status === 1 && drawYesContent()}
{status === 2 && drawNoContent()}
</>
);
}
export default Radio;

#bgaynor78 is right, but I would prefer something like the following, because you will not create an invisible dom node
{
this.state.clickedYes && (<div>This shows when the radioYes input is clicked</div>)
}

You could just simply add a style declaration to your div you want to show, then just hook that up to your state object.
<div style={{ display: this.state.clickedYes ? 'block' : 'none'}}>This shows when the radioYes input is clicked</div>

Related

Checkboxes in child component, how to uncheck every other one when one is checked

fairly new to react, so sorry in advanced. I have a need where I need to uncheck any checked checkboxes if one of them are checked. This component is a grandchild component of my app.js
App.js:
class App extends Component {
constructor (props) {
super (props);
this.state = {
data:[
{
id:'player1',
toggleId: 'audio0',
checked:false,
isAlt:false
},
{
id:'player2',
toggleId: 'audio1',
checked:false,
isAlt: true
},
{
id:'player3',
toggleId: 'audio2',
checked:false,
isAlt:false
},
{
id:'player4',
toggleId: 'audio3',
checked:false,
isAlt: true
}
]
}
}
render(){
return (
<div className="App">
<Notice/>
{this.state.data.map((dynamicComponent, i) =>
<AudioPlayer key = {i} componentData = {dynamicComponent}/>)
}
{/* {audioMap.map(i => {
return <AudioPlayer toggleId={this.state.toggleId[i]} checked={this.state.checked[i]}/>
})} */}
</div>
);
}
}
export default App;
In the audio player component, I have a state for active and setActive and am rendering a toggle switch child component:
AudioPlayer.js:
const [checked, setChecked] = useState(props.componentData.checked);
{/*toggle switch */}
<div className="toggleSwitch">
<ToggleSwitch id={props.componentData.toggleId} checked={checked} onChange={checked => setChecked(checked)} />
</div>
ToggleSwitch.js (taken from https://www.sitepoint.com/react-toggle-switch-reusable-component/):
const ToggleSwitch = ({ id, name, checked, onChange, optionLabels, small, disabled }) => {
function handleKeyPress(e){
if (e.keyCode !== 32) return;
e.preventDefault();
onChange(!checked)
console.log('clicked');
}
return (
<div className={"toggle-switch" + (small ? " small-switch" : "")}>
<input
type="checkbox"
name={name}
className="toggle-switch-checkbox"
id={id}
checked={checked}
onChange={e => onChange(e.target.checked)}
disabled={disabled}
/>
{id ? (
<label className="toggle-switch-label"
htmlFor={id}
tabIndex={ disabled ? -1 : 1 }
onKeyDown={ (e) => { handleKeyPress(e) }}>
<span
className={
disabled
? "toggle-switch-inner toggle-switch-disabled"
: "toggle-switch-inner"
}
data-yes={optionLabels[0]}
data-no={optionLabels[1]}
tabIndex={-1}
/>
<span
className={
disabled
? "toggle-switch-switch toggle-switch-disabled"
: "toggle-switch-switch"
}
tabIndex={-1}
/>
</label>
) : null}
</div>
);
}
// Set optionLabels for rendering.
ToggleSwitch.defaultProps = {
optionLabels: ["On", "Off"],
};
ToggleSwitch.propTypes = {
id: PropTypes.string.isRequired,
checked: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
name: PropTypes.string,
optionLabels: PropTypes.array,
small: PropTypes.bool,
disabled: PropTypes.bool
};
export default ToggleSwitch;
As you can see, I'm rendering four of the same child component, and each of them have a nested toggleSwitch/checkbox. The app.js is setting the checked to false onLoad. I need to make it such that I need to uncheck any active checkbox if one gets checked.If one is checked, then uncheck any active ones. From what I understand, I need to pass data from the child to the parent, but I'm not sure how to do that. Can I even affect the state in the parent? From what I understand, I shouldn't be using props to set the state data. Any help would be appreciated. Thank you

How do you update state in functional components in React?

I'm running into the issue where I have created a functional component to render a dropdown menu, however I cannot update the initial state in the main App.JS. I'm not really sure how to update the state unless it is in the same component.
Here is a snippet of my App.js where I initialize the items array and call the functional component.
const items = [
{
id: 1,
value:'item1'
},
{
id: 2,
value:'item2'
},
{
id: 3,
value:'item3'
}
]
class App extends Component{
state = {
item: ''
}
...
render(){
return{
<ItemList title = "Select Item items= {items} />
And here is my functional componenet. Essentially a dropdown menu from a YouTube tutorial I watched (https://www.youtube.com/watch?v=t8JK5bVoVBw).
function ItemList ({title, items, multiSelect}) {
const [open, setOpen] = useState (false);
const [selection, setSelection] = useState([]);
const toggle =() =>setOpen(!open);
ItemList.handleClickOutside = ()=> setOpen(false);
function handleOnClick(item) {
if (!selection.some(current => current.id == item.id)){
if (!multiSelect){
setSelection([item])
}
else if (multiSelect) {
setSelection([...selection, item])
}
}
else{
let selectionAfterRemoval = selection;
selectionAfterRemoval = selectionAfterRemoval.filter(
current =>current.id == item.id
)
setSelection([...selectionAfterRemoval])
}
}
function itemSelected(item){
if (selection.find(current =>current.id == item.id)){
return true;
}
return false;
}
return (
<div className="dd-wraper">
<div tabIndex={0}
className="dd-header"
role="button"
onKeyPress={() => toggle(!open)}
onClick={() =>toggle(!open)}
onChange={(e) => this.setState({robot: e.target.value})}
>
<div className="dd-header_title">
<p className = "dd-header_title--bold">{title}</p>
</div>
<div className="dd-header_action">
<p>{open ? 'Close' : 'Open'}</p>
</div>
</div>
{open && (
<ul className ="dd-list">
{item.map(item =>(
<li className="dd-list-item" key={item.id}>
<button type ="button"
onClick={() => handleOnClick(item)}>
<span>{item.value}</span>
<span>{itemSelected(item) && 'Selected'}</span>
</button>
</li>
))}
</ul>
)}
</div>
)
}
const clickOutsideConfig ={
handleClickOutside: () => RobotList.handleClickOutside
}
I tried passing props and mutating the state in the functional component, but nothing gets changed. I suspect that it needs to be changed in the itemSelected function, but I'm not sure how. Any help would be greatly appreciated!
In a function component, you have the setters of the state variables. In your example, you can directly use setOpen(...) or setSelection(...). In case of a boolean state variable, you could just toggle by using setOpen(!open). See https://reactjs.org/docs/hooks-state.html (Chapter "Updating State") for further details.
So you need to do something like below . Here we are passing handleChange in parent Component as props to the child component and in Child Component we are calling the method as props.onChange
Parent Component:
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
value :''
}
}
handleChange = (newValue) => {
this.setState({ value: newValue });
}
render() {
return <Child value={this.state.value} onChange = {this.handleChange} />
}
}
Child Component:
function Child(props) {
function handleChange(event) {
// Here, we invoke the callback with the new value
props.onChange(event.target.value);
}
return <input value={props.value} onChange={handleChange} />
}

Show and hide looped elements in ReactJs

I loop through an array of elements:
this.props.connections.map((connection) => (
For each element in this array a card is created. In this card, I implemented a toogle button:
<div id="bookmarkIcon">
{this.state.available ? (
<Tab onClick={this.handleChange} icon={<StarBorderIcon/>}
aria-label="StarBorder"/>) : <Tab onClick={this.handleChange} icon={<StarIcon/>}
aria-label="StarIcon"/>}
</div>
The handle change method changes the value of available to false. The problem is that then I change the state and therefore, ever icon toggles, but I just want to toggle the icon I clicked on. How can I achieve this?
You can create an object which keeps the state as keys.
Here is a working example:
hidden will look something like this {0: true, 1: true, 2: false}
so we can update the corresponding items by their index.
https://codesandbox.io/s/intelligent-black-83cqg?file=/src/App.js:0-577
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [hidden, setHidden] = useState({});
const list = ["aa", "bb", "cc", "dd"];
const toggleHide = index => {
setHidden({ ...hidden, [index]: !hidden[index] });
};
return (
<div className="App">
{list.map((item, index) => (
<div>
{!!hidden[index] && <span>[HIDDEN]</span>}
{!hidden[index] && <span>[VISIBLE]</span>}
{item} <span onClick={e => toggleHide(index)}>x</span>
</div>
))}
</div>
);
}
Class-Based Component
class PrivacyPolicyDetails extends Component {
constructor(props) {
super(props);
this.state ={
resultData:[],
error:false ,
active: false,
activeIdList:[]
}
this.toggleClass.bind(this);
}
componentDidMount() {
setting.getQuestionAnswerByType('privacy-policy')
.then(res =>{
if(res.data.questionAnswerList.length > 0){
this.setState({
resultData: res.data.questionAnswerList,
})
}else{
this.setState({
error:true
});
}
}
);
}
toggleClass(id) {
const currentState = this.state.active;
this.setState({ active: !currentState});
if(this.state.activeIdList.find(element => element == id)){
this.state.activeIdList = this.state.activeIdList.filter(item => item !== id);
}else{
this.state.activeIdList.push(id);
}
}
render() {
const { product, currency } = this.props;
const {resultData,error,activeIdList} = this.state;
return (
<div>
<h1>Privacy Policy</h1>
{resultData && resultData.length > 0 ? resultData.map(each_policy =>
<div className="item">
<div className="question"
onClick={() => this.toggleClass(each_policy.question_answer_repository_id)}
>
{each_policy.question}
</div>
<p className={(activeIdList.find(element => element == each_policy.question_answer_repository_id))? "active-div" :"hide"}>
<div className="answer">{each_policy.answer}</div>
</p>
</div>
):''}
</div>
);
}
}
const mapStateToProps = (state) => {
return state.setting;
};
export default connect(mapStateToProps)(PrivacyPolicyDetails);
css
.hide{
display: none;
overflow:hidden;
}
.active-div{
display: block;
overflow:hidden;
}
Make the card into its own component and implement the state of the toggle inside of that component. In your parent component just map each card into one of these components. Each card will have its own toggle which uses the state of the card to determine how it should display.

React: Trigger button click from array map by another child

I have a parent component App and it has a child Content & Trigger. From the Content component, I have an array of content with radio button and a hidden button. The Trigger component has only one button. 🤔
My question is, how can I trigger a button click inside the Content component from the Trigger component depending on what the user selected on the Content component. 🤯
If my explanation is hard to understand, maybe my code does. Thank you. 🙏
CodeSandbox Sample
https://codesandbox.io/s/laughing-kirch-g2r10?fontsize=14&hidenavigation=1&theme=dark
App.js
import React from "react";
import Content from "./Content";
import Trigger from "./Trigger";
import "./styles.css";
class App extends React.PureComponent {
state = {
selectedOption: ""
};
onRadioButtonChange = name => {
this.setState({
selectedOption: name
});
};
onClickTriggerButton = e => {
const { selectedOption } = this.state;
e.preventDefault();
switch (selectedOption) {
case "opt1":
console.log("trigger click on option 1");
break;
case "opt2":
console.log("trigger click on option 2");
break;
case "opt3":
console.log("trigger click on option 3");
break;
default:
console.log("Select a method...");
}
};
render() {
return (
<div className="App">
<Content onRadioButtonChange={this.onRadioButtonChange} />
<Trigger onClickTriggerButton={this.onClickTriggerButton} />
</div>
);
}
}
export default App;
Content.js
import React from "react";
class Content extends React.PureComponent {
render() {
const { onRadioButtonChange } = this.props;
const tabs = [
{
name: "option_1_name",
content: (
<div className="Option-Method">
<input
type="radio"
name="group"
onChange={() => onRadioButtonChange("opt1")}
/>
Option Medthod 1 - Randon text...
<button
hidden
onClick={() => console.log("option 1 button clicked!")}
/>
</div>
)
},
{
name: "option_2_name",
content: (
<div className="Option-Method">
<input
type="radio"
name="group"
onChange={() => onRadioButtonChange("opt2")}
/>
Option Medthod 2 - Randon text...
<button
hidden
onClick={() => console.log("option 2 button clicked!")}
/>
</div>
)
},
{
name: "option_3_name",
content: (
<div className="Option-Method">
<input
type="radio"
name="group"
onChange={() => onRadioButtonChange("opt3")}
/>
Option Medthod 3 - Randon text...
<button
hidden
onClick={() => console.log("option 3 button clicked!")}
/>
</div>
)
}
];
return (
<form className="Content">
<fieldset id="group">
{tabs.map((attribute, index) => {
const key = `${attribute.name}-${index}`;
return (
<div key={key} className="Option">
{attribute.content}
</div>
);
})}
</fieldset>
</form>
);
}
}
export default Content;
Trigger.js
import React from "react";
class Trigger extends React.PureComponent {
render() {
const { onClickTriggerButton } = this.props;
return (
<div className="Trigger">
<button onClick={onClickTriggerButton}>Trigger Selected Option</button>
</div>
);
}
}
export default Trigger;
Pass ref to the Content component and for each hidden button check for the selectedOption if that matches set ref for that hidden button. Also wrap the Content component in React.forwardRef.
<button
hidden
ref={"opt1" === selectedOption ? ref : null}
onClick={() => console.log("option 1 button clicked!")}
/>
https://codesandbox.io/s/strange-hodgkin-jm84w?file=/src/Content.js:507-671

Conditional rendering based on user input

I've just started learning React and am struggling with conditional rendering. I want to render components based on form input but i'm not sure what needs to be done or where it needs to be executed.
I have imported my Form component which has the input I want to use and have another component like this:
import React, {Component} from 'react';
import Form from './Form';
import CardOne from './CardOne';
import CardTwo from './CardTwo';
import CardThree from './CardThree';
export default class CardContainer extends Component {
render(){
return (
<div>
<CardOne />
<CardTwo />
<CardThree />
</div>
)
}
}
I basically want to be able to show certain Cards if the value of the input is greater than X when the form is submitted, but I don't know how to target an imported component.
This is my Form component:
export default class Form extends Component {
state = {
number: ''
};
change = (e) => {
this.setState({
[e.target.name]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state);
this.setState({
number: ''
})
};
render(){
return (
<form>
<label>Number</label>
<input
type="number"
name="number"
placeholder="Number"
value={this.state.number}
onChange={e => this.change(e)} />
<button onClick={e => this.onSubmit(e)}>Submit</button>
</form>
)
}
}
Any help will be massively appreciated!
I have redesigned your Form component , Below is my code. . Let me know if u faced any issues on that .
import React, { Component } from 'react';
import CardOne from './CardOne';
import CardTwo from './CardTwo';
import CardThree from './CardThree';
export default class Form extends Component {
state = {
number: '',
showOne:true,
showTwo:false,
showThree:false,
userInputValue:''
};
change = (e) => {
this.setState({
userInputValue: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state);
if (this.state.userInputValue > 10 && this.state.userInputValue <20 ){
this.setState({
showTwo: true,
})
}
if (this.state.userInputValue > 20 && this.state.userInputValue < 30) {
this.setState({
showThree: true,
})
}
};
render() {
return (
<div>
<form>
<label>Number</label>
<input
type="number"
name="number"
placeholder="Number"
value={this.state.userInputValue}
onChange={e => this.change(e)} />
<button onClick={e => this.onSubmit(e)}>Submit</button>
</form>
<div>
{this.state.showOne ?
<CardOne />
:
<div></div>
}
{this.state.showTwo ?
<CardTwo />
:
<div></div>
}
{this.state.showThree ?
<CardThree />
:
<div></div>
}
</div>
</div>
)
}
}
// What i wrote above is your base functionality . You reedit the condition depends on ur requirement .
This is what I came up with following your logic of card rendering. I did not change Form coponent but rather worked on the Container
export default class CardContainer extends Component {
constructor(props) {
super(props);
state = {
number: 0,
}
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit=(number)=>{
this.setState({ number: number });
}
render(){
let i=Math.floor(this.state.number/10)
return (
<div>
<Form onSubmit={() => this.onFormSubmit(number)}
[<CardOne />, <CardTwo />, <CardThree/>].slice(0,i).map(card =>
{card}
)
</div>
)
}
}
I would use render prop for this kind of problem. You can research more about render props but basically your CardContainer component will not render those cards component statically as it is. It will return props.children instead.
And then you will have a function (i.e function TestX) that will have a conditional to check what the value of X is. This is the function that will return either , , based on what X is. The function TestX will receive props from CardContainer, including the value of X that is read from the state.
So I will just use CardContainer component with as its child.

Categories