Toggling state with dynamic key value pair - reactjs

I have been trying to toggle state using dynamic key value pairs but it doesn't seem to happen.
Here is the state:
constructor(props) {
super(props);
this.state = {
firecrackerAnimation: false,
mainImageBounceAnimation: false,
flowersFallingAnimation: false,
};
}
This is the code I am using to toggle state
changeAnimation = e => {
this.setState(
{
[e.target.value]: !(this.state[event.target.value]),
},
() => {
console.log(this.state);
}
);
Below is where I am using it inside my render()
<div className="form-row">
<span className="form-label">Animations</span>
<input
className=""
type="checkbox"
value="firecrackerAnimation"
onClick={this.changeAnimation}
checked={this.state.firecrackerAnimation}
/>{" "}
Fire Cracker Animation <br />
<input
className=""
type="checkbox"
value="mainImageBounceAnimation"
onChange={this.changeAnimation}
checked={this.state.mainImageBounceAnimation}
/>{" "}
Main Image Bounce <br />
<input
className=""
type="checkbox"
value="flowersFallingAnimation"
onChange={this.changeAnimation}
checked={this.state.flowersFallingAnimation}
/>{" "}
Flowers Falling Animation <br />
</div>

There are several mistakes I've pointed out:
You should use e.target.name in order to get the name of the checkbox being clicked.
You have to provide name for checkboxes, not the value
WORKING DEMO
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
firecrackerAnimation: false,
mainImageBounceAnimation: false,
flowersFallingAnimation: false,
};
}
changeAnimation = (e) => {
this.setState(
{
[e.target.name]: !(this.state[e.target.name]),
},
() => {
console.log(this.state);
})
}
render() {
return (
<div className="form-row">
<span className="form-label">Animations</span>
<input
className=""
type="checkbox"
name="firecrackerAnimation"
onChange={this.changeAnimation}
checked={this.state.firecrackerAnimation}
/>{" "}
Fire Cracker Animation <br />
<input
className=""
type="checkbox"
name="mainImageBounceAnimation"
onChange={this.changeAnimation}
checked={this.state.mainImageBounceAnimation}
/>{" "}
Main Image Bounce <br />
<input
className=""
type="checkbox"
name="flowersFallingAnimation"
onChange={this.changeAnimation}
checked={this.state.flowersFallingAnimation}
/>{" "}
Flowers Falling Animation <br />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
.as-console-wrapper { max-height: 50% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Change your changeAnimation function as follows:
changeAnimation(e){
var value = e.target.value;
this.setState({[value]: !(this.state[value])});
}
Here is the fiddle.

you have problem with your change animation event
changeAnimation = e => {
this.setState(
{
// [e.target.value]: !(this.state[event.target.value]),
//here you have to change like
this.state[e.target.value]: !(this.state[event.target.value]),
},
() => {
console.log(this.state);
}
);

The other responses are correct in that you can setState with dynamic keys and variables, however React recommends against using state inside setState.
From the docs:
"React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state."
- https://reactjs.org/docs/state-and-lifecycle.html
You can take the same idea as the other comments mention and make setState accept a function instead. I used this in my code (button was defined in an outer function).
this.setState((prevState) => ({
[button]: !prevState[button]
}));

Related

How to show/hide div in React?

I want to show <div nameClass="showName"> when button is clicked and this.state.name's value is not null.
The showResult state check name's value is null or not, but this isn't work I guess.
I don't know how to fix it.
import React, { Component } from 'react';
class PhoneForm extends Component{
state = {
name : '',
showResults : false
}
handleChange = (e) => {
this.setState({
name: e.target.value
})
}
onClick=(e)=>{
this.setState({
showResults: this.state.name===null ? false : true
})
}
render(){
return (
<form>
<input
placeholder="name"
value={this.state.name}
onChange={this.handleChange}/>
<button onClick={this.onCkick}>클릭!</button>
<div nameClass="showName" style={{display:(this.state.showResults? 'block':'none')}}>{this.state.name}</div>
</form>
);
}}
export default PhoneForm;
You have a small typo in your render method. Your change event handler is called onClick, not onCkick.
You must also make sure to use preventDefault on the event when the form is submitted, or the browser will reload.
class PhoneForm extends React.Component {
state = {
name: "",
showResults: false
};
handleChange = e => {
this.setState({
name: e.target.value
});
};
onClick = e => {
e.preventDefault();
this.setState({
showResults: this.state.name === null ? false : true
});
};
render() {
return (
<form>
<input
placeholder="name"
value={this.state.name}
onChange={this.handleChange}
/>
<button onClick={this.onClick}>클릭!</button>
<div
nameClass="showName"
style={{ display: this.state.showResults ? "block" : "none" }}
>
{this.state.name}
</div>
</form>
);
}
}
ReactDOM.render(<PhoneForm />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
When the input is empty it will show nothing hence we don't need to check whether the input has a value or not.
What is needed to to toggle the visibility for on the onClick function.
Set the <button/> type attribute to 'button' if you dont want to refresh the page all the time.
like: <button type="button" onClick={this.onClick}>클릭!</button>
Or trigger the preventDefault() on the event.
class PhoneForm extends React.Component {
state = {
name: "",
showResults: true
};
handleChange = e => {
this.setState({
name: e.target.value,
showResults: true
});
};
onClick = e => {
this.setState({
showResults: !this.state.showResults
});
};
render() {
return (
<form>
<input
placeholder="name"
value={this.state.name}
onChange={this.handleChange}
/>
<button type="button" onClick={this.onClick}>클릭!</button>
<div
nameClass="showName"
style={{ display: this.state.showResults ? "block" : "none" }}
>
{this.state.name}
</div>
</form>
);
}
}
ReactDOM.render(<PhoneForm />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

How to get the text field value and push that value to an arrayList

How to get the text field value and push that value to an arrayList in react js?
I want to get the value from the text box and push it to Modules array so that i can render the values by iterating it.
I tried to use ref but getting error.
Can you help me?
constructor(props) {
super(props);
this.state={
module:'',
Modules: []
}
}
change (event){
this.setState({
[event.target.name]:event.target.value
});
};
createModule (e) {
e.preventDefault();
console.log("submitted",this.state.module);
this.setState(previousState => ({
...state,
thisModules: [...previousState.Modules, 'new value']
}));
};
render(){
return(
<form className="form-inline">
<div className="form-group">
Module Name:
<input type="text" id="module"
name="module"
placeholder="module"
className="form-control"
ref="Module"
value ={this.state.module}
onChange={event => this.change(event)}/>
<button type="submit" className="btn btn-primary" onClick={(event) => this.createModule(event)}>Add Module</button>
</div>
</form>
mylist.push(document.getElementById('textbox_id').value)
with mylist as your list and textbox_id as the id of the textbox should work.
Consider this is plain javascript as I don't really see any difference with react.
The main problem from running your code was that in createModule you weren't putting this in front of state. If you'd given details of the error this would have helped.
There were a few other typos, and a work solution is below.
class ModuleList extends React.Component {
constructor(props) {
super(props);
this.state={
module:'',
Modules: []
}
}
change (event){
this.setState({
[event.target.name]:event.target.value
});
}
createModule (e) {
e.preventDefault();
console.log("submitted",this.state.module);
this.setState(previousState => ({
...this.state,
Modules: [...previousState.Modules, this.state.module]
}));
};
render(){
return (
<form className="form-inline">
<div className="form-group">
Module Name:
<input type="text" id="module"
name="module"
placeholder="module"
className="form-control"
ref="Module"
value={this.state.module}
onChange={event => this.change(event)}/>
<button type="submit" className="btn btn-primary" onClick={(event) => this.createModule(event)}>Add Module</button>
</div>
<ul>
{
this.state.Modules.map(
(m) => <li>{m}</li>
)
}
</ul>
</form>
);
}
}
ReactDOM.render(
<ModuleList />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<p>My App:</p>
<div id='root' />

setState() and its async nature is not my friend... what can I do?

I'm aware that my code is terrible and awful, but am struggling here and would appreciate some help. Basically, I'm trying to create a form, where after the button at the bottom is clicked, it will display the information on state. I've tried doing this via a ternary - where if this.state.display is true, it will show as true, and if false, it will show the form.
I believe the problem would have to do with the asynchronous nature of setState. Because setState is slow, this.state.display never truly gets set to true, and therefore the terniary never really gets to execute properly. I just don't know how I would fix this. I've played with shouldComponentUpdate and componentWillUpdate, but it's not been very helpful.
Does anyone have any suggestions? I'm a newb and recognize that this is far from quality code. Would just love for someone's gentle guidance. Thanks.
class Application extends React.Component {
constructor(props){
super(props)
this.state = {
display: false,
firstName : "",
lastName : "",
phone : null,
email : "",
};
}
shouldComponentUpdate() {
if (this.state.display) {
return true;
}
return false;
}
render() {
return (
{ this.state.display ?
<div>
<h1>{this.state.firstName}</h1>
<h1>{this.state.lastName}</h1>
<h1>{this.state.phone}</h1>
<h1>{this.state.email}</h1>
</div> :
<div className="header">
<h1>Greetings!</h1>
</div>
<div className="inputform">
<input placeholder="First Name" onChange={(e) => {this.setState({firstName: e.target.value})}} />
<input placeholder="Last Name" onChange={(e) => {this.setState({lastName:e.target.value})}} />
<input placeholder="Phone Number" onChange={(e) => {this.setState({phone:e.target.value})}} />
<input placeholder="Email Address" onChange={(e) => {this.setState({email:e.target.value})}} />
<button onClick={this.setState({display: true})}>Submit</button>
</div>
}
);
}
}
ReactDOM.render(<Application />
, document.getElementById('app'));
Here is a working version of your class:
class Application extends React.Component {
constructor(props){
super(props)
this.state = {
display: false,
firstName : "",
lastName : "",
phone : null,
email : "",
};
}
_renderForm() {
return (
<div>
<div className="header">
<h1>Greetings!</h1>
</div>
<div className="inputform">
<input placeholder="First Name" onChange={(e) => {this.setState({firstName: e.target.value})}} />
<input placeholder="Last Name" onChange={(e) => {this.setState({lastName:e.target.value})}} />
<input placeholder="Phone Number" onChange={(e) => {this.setState({phone:e.target.value})}} />
<input placeholder="Email Address" onChange={(e) => {this.setState({email:e.target.value})}} />
<button onClick={ () => this.setState({ display: true }) }>Submit</button>
</div>
</div>
);
}
_renderData() {
return (
<div>
<h1>{this.state.firstName}</h1>
<h1>{this.state.lastName}</h1>
<h1>{this.state.phone}</h1>
<h1>{this.state.email}</h1>
</div>
)
}
render() {
return this.state.display ? this._renderData() : this._renderForm();
}
}
ReactDOM.render(<Application />, document.getElementById('app'));
The main problem was that you were calling setState immediately during render. While you should pass a function that calls it.
You need to pass a functin to onClick handler of button. Preferably like this
handler = () => {
this.setState({display: true})
}
render(){
<button onClick={this.handler}>Submit</button>
}

react js - how to populate values based on another DOM element value

I have 2 input boxes. Based on one input(1) box value (on key up event), I am populating another input(2) box value. Currently, I am using document.getElementByID option to retrieve element id to populate the values. Is it recommended in react js ? pls suggest. Like to find a better way to to this in react js.
handleChange(e) {
if(document.getElementById("getId").value.length > 4) {
console.log("a")
document.getElementById("getName").value =
document.getElementById("getId").value
}
}
render () {
return (
<div>
<Card>
<div>
<label>Id</label>
<input type="text" id="getId" onKeyUp= {this.handleChange.bind(this)}/>
<div>
<label>Name</label>
<input type="text" id="getName" readOnly/>
</div>
</div>
</Card>
</div>
);
You could store the value of the first input box in your component state and set the value of the second input box to the value from the state.
Then when the value of the input box changes, update the state, using the handleChange method, which in turn re-renders the component updating the second input box.
...
constructor(props) {
super(props)
this.state = {
inputText: ''
}
this.handleChange = this.handleChange.bind(this)
}
handleChange({ target }) {
if (target.value.length > 4) {
this.setState({
inputText: target.value
})
}
}
render () {
return (
<div>
<Card>
<div>
<label>Id</label>
<input type="text" id="getId" onKeyUp={ this.handleChange } />
<div>
<label>Name</label>
<input type="text" id="getName" value={ this.state.inputText } />
</div>
</div>
</Card>
</div>
)
}
...
You can handle issue with two ways.
First way is to use React refs and DOM.
So in code below I have done two things, I have added ref props to getName input and accessed it from handleChange method by this.refs.inputOfName', as well ase.targetas your DOM input without accessing again bygetElementById`.
handleChange(e) {
let value = e.target.value;
if (value.length > 4) {
this.refs.inputOfName.value = value
}
}
render() {
return (
<div>
<Card>
<div>
<label>Id</label>
<input type="text" id="getId" onKeyUp=
{this.handleChange.bind(this)} />
<div>
<label>Name</label>
<input type="text" id="getName" ref="inputOfName" readOnly />
</div>
</div>
</Card>
</div>
);
You can read more about refs here.
Second way is to use states.
I suggest to use states because it's more React "style" approach as well as one of the React advantages, so spend more time learning about state and lifecycle of React.
You can read more about states here.
handleChange(e) {
let value = e.target.value;
if (value.length > 4) {
this.setState({
name: value
});
}
}
render() {
return (
<div>
<Card>
<div>
<label>Id</label>
<input type="text" id="getId" onKeyUp=
{this.handleChange.bind(this)} />
<div>
<label>Name</label>
<input type="text" id="getName" value={this.state.name} readOnly />
</div>
</div>
</Card>
</div>
);
}
As already mention, It's not common to user getElementById within react component, think of what will happen if you will have 2 components rendered.
You can use component state to update your elements.
constructor(props, context) {
super(props, context);
// This will represent your component state to hold current input value.
this.state = { value: "" };
// Do handler bindings in one place and not inside the render
// function as it will create a new function reference on each render.
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({value: e.target.value});
}
render () {
return (
<div>
<Card>
<div>
<label>Id</label>
<input type="text" id="getId" onKeyUp={this.handleChange}/>
<div>
<label>Name</label>
<input type="text" value={this.state.value} readOnly/>
</div>
</div>
</Card>
</div>
);
}

Setting checkbox with click of another element - react

What I am trying to do here is set the value of the checkbox to 'checked' (because it is styled as a slider) when I click on the <i className='icon-gear'. I'm having trouble accessing input to change it's state. Am I missing something here or am I going about it the wrong way/what would be the better way to approach it? Thanks ahead of time for the help!
const Slider = () => {
return (
<div className="slider-container">
<label className="switch">
<input type="checkbox" />
<span className="slider round" />
</label>
<p className="batch-slider-title"> Batch Widget </p>
</div>
);
};
class Settings extends Component {
constructor() {
super();
this.state = {
isWidgetDisplayed: false,
checked: false,
};
this.showWidget = this.showWidget.bind(this);
}
showWidget() {
this.setState({
isWidgetDisplayed: !this.state.isWidgetDisplayed,
checked: !this.state.checked,
});
}
mouseOut() {
this.setState({showing: false});
}
mouseOver() {
this.setState({showing: true});
}
render() {
const batchWidget = this.state.isWidgetDisplayed ? <BatchWidget /> : null;
const slider = showing => {
if (showing === true) {
return <Slider />;
}
return null;
};
return (
<div>
<div className="settings">
<i className="icon-gear" onMouseOut={() => this.mouseOut()} onMouseOver={() => this.mouseOver()} onClick={this.showWidget} />
</div>
{slider(this.state.showing)}
{batchWidget}
</div>
);
}
}
<input type="checkbox" /> should be <input type="checkbox" checked={this.props.checked}/>
And it should receive those props via <Slider checked={this.state.checked}/>

Resources