Using functional setState in forms - reactjs

I have been learning react and on setState i get about functional setState, i wanted to implement this on the forms to see how it works ( please don't give me counter example,i am seeing if it can be implemented in forms for usage only ).
I am trying to do this because i saw similar approach in a github but he had included all the things inside the single object, so he is doing it easily. But my question is can i do the same but without including my form properties like username and password inside object. I am talking about this repo => Form Container. What do you people recommend? How may i can do ? Thanks !
My form code is like this:
index.js
import React,{ Component } from 'react';
import ReactDOM from 'react-dom';
class Form extends Component{
constructor(props){
super(props);
this.state = {
name: "",
age: "",
};
}
handleInput = (e) => {
let name = e.target.name;
let value = e.target.value;
this.setState({ [name]: value });
}
//The block where i am trying to implement the function setState
handleInput = (e) => {
let name = e.target.name;
let value = e.target.value;
this.setState( state => ({
name:{state.name,[name]: value}
}));
}
render(){
return(
<div>
<label> Name:
<input type="text" name="name" value={this.state.name} onChange={this.handleInput} />
</label>
<br />
<label> Age:
<input type="text" name="age" value={this.state.age} onChange={this.handleInput} />
</label>
</div>
);
}
}
ReactDOM.render(<Form />, document.getElementById('root'))

handleInput = ({ target }) => {
const { name, value } = target;
this.setState({ [name]: [value] });
}
//Can even boil down to one line of code
handleInput = ({ target }) => this.setState({ [target.name]: [target.value] })
You may try the code above. It's pretty concise and not sure how to elaborate on it. We can discuss about my approach in comment
UPDATES:
let value = e.target.value;
this.setState( prevState => ({
newUser : { ...prevState.newUser, name: value }
}), () => console.log(this.state.newUser))
The above code was copied from the link you commented which in our case, should be implemented as below:
handleInput = ({ target }) => {
const { name, value } = target;
this.setState(prevState => ({ ...prevState, [name]: value }));
}

Related

Why my component is not changing state when I trigger the function

I am in new in React and I am trying to change the state when the user type some values in the inout. For a reason the component does not seem to work. Could anyone explain me why I am not succeeding in implementing this function? Thanks, Valentino
import React, { Component } from 'react';
class Stake extends Component {
state = ({
userStake: null
});
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
this.setState({
userStake: [...userStake, newStake]
})
}
render() {
return (
<div>
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
/>
</form>
</div >
);
}
}
export default Stake;
to accomplish a controlled input you should add the property value pointing to the respective state, and onChange that will handle its state update. for your onSubmit you use another handler specific to it. you should also fix your handleChange to update its value correctly:
class Stake extends Component {
state = ({
userStake: [],
input: ''
});
handleUserStake = (e) => {
let input = e.target.value;
this.setState({ input });
}
handleSubmit = () => {
e.preventDefault();
let newStake = this.state.input;
this.setState({
userStake: [...this.state.userStake, newStake],
input: '',
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
value={this.state.input}
onChange={this.handleUserStake}
required
/>
</form>
</div>
);
}
}
export default Stake;
You need to first get userStake from the state
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
// you need to first get it from the state before updating
const { userStake } = this.state;
this.setState({
userStake: [...userStake, newStake]
})
}
Firstly you should create constructor for your component with state and binded `handleUserStakez method.
Because you are waiting for the submit event from form you would use ref for the input:
this.inputRef = React.createRef();
ref={this.inputRef}
Full code here:
class Stake extends Component {
constructor(props) {
super(props);
this.state = {
userStake: ""
};
this.handleUserStake = this.handleUserStake.bind(this);
this.inputRef = React.createRef();
}
handleUserStake = (e) => {
e.preventDefault();
let newStake = this.inputRef.current.value;
console.log("newStake", newStake);
this.setState({
...this.state,
userStake: newStake
});
};
render() {
return (
<div>
STATE: {this.state.userStake}
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
ref={this.inputRef}
/>
</form>
</div>
);
}
}
this should work ...
state = {
userStake: [],
};
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.stake.value;
this.setState((state) => ({
userStake: [...state.userStake, newStake],
}));
};
what was problem? :-
getting value you need to add NAME from target which is form to get field value. like ...
let newStake = e.target.stake.value;
getting current state value, your were just getting userStake out of nowhere so it was giving undefined error.
this.setState((state) => ({ userStake: [...state.userStake, newStake], }));
make default value to [] for userStake in state obj.
userStake: []
I think I found the solution. The problem was that I had to write [...this.state.userStake, newStake]

Can't type in React input text field in Todo app

I am making a todo app in React.js but stuck in this part. I can not type in input field. Please help me.
import React, { Component } from 'react';
export default class AddItem extends Component {
state =
{
title: "",
done: false
}
changeTitle = (e) =>{
e.preventDefault();
this.setState = ({
title: e.target.value
});
}
addNewItem = (item) => {
item.preventDefault();
let newTask = {
title: this.state.title,
done: false
};
this.props.additem(newTask);
this.setState = ({
title: ""
});
}
render() {
return (
<div>
<form>
<input
type="text"
placeholder="add task name."
value={this.state.title}
onChange= {this.changeTitle}
/>
<button type = "button" onClick= {this.addNewItem} >submit</button>
</form>
</div>
)
}
}
this.setState is a function that is called with an object containing changes in state. The code you are using here is an assignment not a function call:
this.setState = ({
title: e.target.value // Wrong
});
Instead, call the setState function with the changes/updates in state. the changes are shallow merged and only title is updated here.
this.setState({title:e.target.value});
You will have a similar problem inside addNewItem.

Unable to update parent prop in react

I can insert the input value say "1,2,3" and when backspace it removes all but in the console "1" is still shown i.e., House{props{house{property{rent:1}}}}
I am providing the code here which has 3 files.
(1) house.js
import ValInput from "main/components/val-input";
class House extends Component {
state = {
rent:"",
};
componentDidMount() {
if (this.props.house.rent) {
const { rent} = this.props.house;
this.setState({ rent });
}
}
onChange = (e) => {
const rent = parseInt(e.target.value.replace(string);
this.setState({
rent,
});
};
render(){
const {house} = this.props;
const {rent} = this.state;
...
<ValInput
type="text"
value={ rent }
onChange={e => {
this.onChange(e);
}}
/>
}
(2) val-input\index.js
import React from "react";
import Input from "main/components/input";
const ValInput = props => (
<Input
{...props}
type={props.type ? props.type : "text"}
/>
);
export default valInput;
(3) components/input/index.js
import React from "react";
const noOp = () => {};
const Input = ({
onBlur = xP,
...otherProps
}) => (
<input
onBlur={e => {
e.target.placeholder = placeholder;
onBlur(e);
}}
{...otherProps}
/>
);
export default Input;
The expected result should be, after emptying the value say with backspace, and visit the page next time, the input field should be empty and should not show old value.
Check this CodeSandbox out I replicated your code and if I understood the problem right then fixed it
https://reactjs.org/docs/cross-origin-errors.html
For updating #NaderZouaoui, has given me an example how to do Call back :
1. Child file :
onChange={e => {
this.onChange(e);
}}
onChange = e => {
this.setState({
rent
});
this.props.callback(rent);
};
2. Parent file :
state = {
rent: ""
};
handleChangeRent = newRent => {
this.setState({ rent: newRent });
};
render(){
return(
<House house={{ rent }} callback={this.handleChangeRent} />
);
}

how to get the checked value of a radio button using react

I have below radio button Component
import React from 'react';
import PropTypes from 'prop-types';
export default class RadioButton extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.props.handleChange(event);
}
render() {
return (
<div>
<input type="radio" name="measureValue" value={this.props.value} onChange={this.handleChange} checked={true}/>
<label>{this.props.value}</label>
</div>
);
}
}
Im using this component as
handleRadioSelect = (event) =>{
this.setState({
selectedRadioValue : event.target.value
})
}
<RadioButton value="Fact" handleChange = { this.handleRadioSelect }/>
Now,I got the error as handleChnage is not a function.
to get value of checked, use the event.target.checked instead of event.target.value, so that:
handleRadioSelect = (event) =>{
this.setState({
radioChecked : event.target.checked
})
}
And your error appear because you need to use the arrow function to this.handleCheck (so you can pass in the event props) so that:
onChange={e => this.handleCheck(e)}
In this case, you do not need to bind it anymore and just use normal function for the handleCheck so that:
handleChange(event) {
this.props.handleChange(event);
}
This is how I normally approach it, hope that helps!
handleChange = (event) => {
let target = event.target;
let name = target.name;
let value = target.type === 'checkbox' ? target.checked : target.value;
this.setState({
[name] : value
})
}
Hope this helps

React Geosuggest doesn't update state

i'm trying to make a weather app, and using external component 'react-geosuggest'.
My problem is, when I update the input (SEE:onChange={this.onInputChange}), that function doesn't take my input, and don't change the state, i.e I get undefined.
What's interesting, i've set initialvalue to be New York, and on submit I get results, without changing input information, so problem lies in updating input information and passing it to function handleOnSubmit.
I've read docs about that component, but couldn't figure it out, it has same values as simple , but something doesn't work.
Thanks!
class SearchBar extends Component {
constructor() {
super()
this.state = {city: 'New York'};
}
onInputChange = (e) => {
this.setState({city: e.target.value});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
this.setState({city: ''});
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Bind the event on the constructor, set the value attribute in the render and remove the setState to empty string that you are doing in the handleOnSubmit event. I am afraid this last one is what it makes not working when you change the input.
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {city: 'New York'};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange = (city) => {
this.setState({city: city});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
value={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Use e.currentTarget.value instead. See this question for more on this.
Also try this:
onChange={this.onInputChange.bind(this)}
If you'd like to be more concise you can write it this way:
<Geosuggest
initialValue={this.state.city}
onChange={(e)=> this.setState({city: e.currentTarget.value})}
types={['(cities)']}
/>
You can also get the value of selected address using onSuggestSelect:
<Geosuggest
ref={el=>this._geoSuggest=el}
placeholder="Search for address"
onSuggestSelect={this.onSuggestSelect}
country='us'
/>
Then access the components like so:
onSuggestSelect(suggest) {
if (!suggest.gmaps) {
return;
}
const components = suggest.gmaps.address_components;
const address = {
street: this.findAddressComponent(components, 'street_number', 'short_name') + ' ' + this.findAddressComponent(components, 'route', 'short_name'),
city: this.findAddressComponent(components, 'locality', 'short_name'),
state: this.findAddressComponent(components, 'administrative_area_level_1', 'short_name'),
zip: this.findAddressComponent(components, 'postal_code', 'short_name'),
}
this.setState({
address
});
}
findAddressComponent(components, type, version) {
const address = components.find(function(component) {
return (component.types.indexOf(type) !== -1);
});
return address[version];
}

Resources