how to change value of an object using reactjs - reactjs

My objective is to change the value of an object and pass the modified object.
Here is the object:
{
id: '12497wewrf5144',
name: 'ABC',
isVisible: 'false'
}
Here is the code:
class Demo extends Component {
constructor(props) {
super(props)
this.state = {
demo: []
}
}
componentDidMount() {
axios
.get('/api/random')
.then(res => {
this.setState({ demo: res.data})
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div>
{this.state.demo.map((user)=>
<h1>{user.name}</h1>
<input type="checkbox" value={user.value} />
)}
</div>
)
}
}
export default Demo
I don't know what to write in onchange method for checkbox to only change the value within the object.
Note: value is string isVisible (we need to change value as boolean)
Can anyone help me in this query?

In order to change a certain key of an object you can use the following
this.setState({
...this.state,
demo: {
...this.state.demo,
isVisible: <NEW VALUE>
}
})

Related

React How to Get Value of a SelectList from a Child Component

I'm working on a form in which one of the input items will be a select list. I am trying to implement the form by using reusable components. The hierarchy is this:
<SignupForm>
<CountrySelectList>
<SelectList>
I am able to get the select list to render, but I am not sure how to pass the needed props to the child componets in order to bind the selection from the drop down list? Here are the components (with some form fields removed for brevity).
SignupForm
class SignupForm extends React.Component {
constructor(props) {
super(props);
this.state = {
country: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
handleSubmit(event) {
event.preventDefault();
let formData = new FormData();
formData.append("Country", this.state.country);;
fetch("api/account/signup", {
method: "POST",
body: formData })
.then(response => response.json())
.then(data => console.log(data));
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<CountrySelectList name="country" value={this.state.country} onChange={this.handleChange} />
<SubmitButton btnText="Submit"/>
</form>
);
}
}
export default SignupForm;
CountrySelectList
class CountrySelectList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: []
};
}
async componentDidMount() {
try {
const response = await fetch('api/location/countries');
const json = await response.json();
this.setState({
data: json,
isLoaded: true
});
} catch (error) {
console.log(error);
}
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <LoadingSpinner/>;
} else {
return (
<SelectListGroup>
<Label label="country" title="Country"/>
<SelectList data={data} value={this.props.value} onChange={this.props.onChange} />
</SelectListGroup>
);
}
}
}
export default CountrySelectList;
SelectList
export default function SelectList({ data, value, onChange, addClass="" }) {
return (
<select
value={value}
className={`form-select ${addClass}`}
onChange={onChange}>
{data.map((data, index) => (
<option key={index} value={data.value}>
{data.text}
</option>
))}
</select>
);
}
This answer has a good explanation of getting data from forms and their component parts.
Get form data in ReactJS
You're kind of doing the same job twice by saving the selection as state and using form -> submit.
If you give your select a name attribute, then in the handleSubmit function, the event parameter will contain a named element that you can get the value from.
<select name='country' ...
Then the function can use
const handleSubmit = (event) => {
console.log(event.target.country.value);
}
The onSubmit event of the form carries all the info, you just have to name the elements.

calling function in React SetState gives error that userName is unlabelled why?

import React,{Component} from 'react'
class Formhandler extends Component {
constructor(props) {
super(props)
this.state = {
userName:""
}
}
changer=(event)=>{
this.setState(()=>{
userName : event.target.value
})
}
render()
{
return(
<div>
<label>UserName</label>
<input type="text" value={this.state.userName} onChange={this.changer}/>
</div>
)
}
}
export default Formhandler
You are getting the error because of invalid syntax.
Update changer function
changer = (event) => {
this.setState({ userName: event.target.value });
};
You need to return an object inside the setState function but you are not that's the source of issue(syntax error).
use a function inside setState when your new state value would depend on your previous state value, where the function passed inside the setState will receive previous state as argument
changer = (e) => {
this.setState((prevState) => ({
userName : e.target.value
})
);
}
pass an object to update the state, use this when it doesn't depend on your previous state value.
changer = (e) => {
this.setState({ userName: e.target.value });
};
import React from "react";
class Formhandler extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
};
}
changer(event) {
this.setState(() => ({
userName: event.target.value,
}));
}
render() {
return (
<div>
<label>UserName</label>
<input
type="text"
value={this.state.userName}
onChange={this.changer.bind(this)}
/>
</div>
);
}
}
export default Formhandler;
It will work, compare your version and this

Unable to change the value in the object

My objective is to change the value of the object to true or false while onchanging the checkbox.
Object contains:
{
id: '12497wewrf5144',
name: 'ABC',
isVisible: 'false'
}
Here is the code:
import React, { Component } from 'react'
class Demo extends Component {
constructor(props) {
super(props)
this.state = {
demo: {}
}
}
componentDidMount() {
axios
.get('/api/random')
.then(res => {
this.setState({ demo: res.data?.[0] })
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div>
<h1>{this.state.demo.name}</h1>
<input type="checkbox" value={this.state.demo.value} />
</div>
)
}
}
export default Demo
I don't know what to write in onchange method for checkbox to only change the value within the object.
Can anyone help me in this query?
<input
type="checkbox"
value={this.state.demo.value}
onChange={(event) => {
this.setState((prevState) => ({
...prevState,
demo: { ...prevState.demo, isVisible: event.target.checked }
}));
}}
/>
Given your state ends up looking like
this.state = {
demo: {
id: "12497wewrf5144",
name: "ABC",
isVisible: "false",
value: false
}
};
You can create a change handler as such
changeHandler = e => {
e.preventDefault();
const { checked } = e.target;
this.setState(prevState => ({
...prevState, // <-- spread existing state
demo: {
...prevState.demo, // <-- spread existing demo
value: checked, // <-- save the input's checked value
}
}))
}
Attach the changeHandler to the onChange event callback
<input
type="checkbox"
onChange={this.changeHandler}
value={this.state.demo.value}
/>
Ciao, you could use onClick event like this:
...
handleClick = (e, data) => {
const demo = { ...this.state.demo };
demo.isVisible = !demo.isVisible;
this.setState({ demo });
}
...
<input type="checkbox" value={this.state.demo.value} onClick={((e) => this.handleClick(e, data))}/>
...

How to update state inside componentDidMount?

I'm using fetch API and I want update the const called state inside the componentDidMount() (with onChange) which are being using in a template string. How do I update this value with onChange?
import React, {Component} from 'react'
class Data extends Component {
constructor() {
super();
this.state = {
items: {},
value: '',
isLoaded: false
}
}
handleChange(e) {
this.setState({value: e.target.value});
}
componentDidMount() {
const state = this.state.value
fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${state}`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render(){
const {isLoaded} = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
}
So, how can I update the value of the const state with onChange?
componentDidMount() is called when the React component has mounted, and it happens only once.
If I understand correctly, you want to call fetch on each change of the value stored under value state property, so the componentDidMount method is not a perfect place to put that kind of logic. You can create a separate method called fetchData and pass the value to it as an argument. Then you can call that method on componentDidMount as well as on each value property change (in our case - onChange event).
import React, { Component } from "react";
class Data extends Component {
constructor(props) {
super(props);
this.state = {
items: {},
value: "America/Chicago",
isLoaded: false
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
const { value } = this.state;
this.fetchData(value);
}
handleChange(event) {
const value = event.target.value;
this.setState({
value
});
this.fetchData(value);
}
render() {
const { isLoaded, value, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<select onChange={this.handleChange} value={value}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
{JSON.stringify(items)}
</div>
);
}
fetchData(value) {
fetch(
`https://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}`
)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json
});
});
}
}
Working demo: https://codesandbox.io/embed/728jnjprmq
Assuming you want to refresh the value of this.state.items when the user changes the value of the select, you can do this in the onChange. However, your code is in a few (incorrect) pieces. Let's start from the top.
First of all, you're setting the value property of state to '', so your componentDidMount function is going to see that value. I assume that's no good, so let's strip that out of componentDidMount entirely. We can move this code to the handleChange function instead, but it'll still need to be changed:
handleChange(e) {
this.setState({value: e.target.value});
fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${e.target.value}`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
Notice my change - we can't access the value from the state, because setState is asynchronous, and so the value hasn't been updated by this point. We know the value comes from the select though.
The other thing you could do to improve this functionality is to turn the select into a controlled component. To do this, you just have to set the value of the field to be controlled by the state of this component. Since you're using an onChange listener for this, it makes the field a controlled component (if you weren't using an onChange, it would be a read-only field.
The loading variable in state appears to be being used incorrectly, I'm guessing you just need to check if there's data in 'items'. I'll remove this for now, but you could come back to this.
render(){
const {isLoaded} = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
Tomasz's code has 2 mistakes: (1) it fetches resources w/o checking if the component has been unmounted; (2) it starts the request w/o updating the UI first.
I would do the following instead:
import React, {Component} from 'react'
class Data extends Component {
constructor() {
super();
this.state = {
items: {},
value: '',
isLoaded: false
}
this._isMounted = false;
// don't forget to bind your methods
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
handleChange(e) {
const value = e.target.value;
this.setState({ value }, () => {
if (!this._isMounted) return;
const url = `http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}`
fetch(url).then((res) => {
if (!this._isMounted) return;
const data = res.json();
this.setState({ isLoaded: true, items: data });
})
});
}
render(){
const { isLoaded } = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
}

Controlled Inputs, displayed values will not update to last digit

i'm using React(Typescript Version) to display some input inside a form.
The problem (as you can see from the image) is that when i update the values, from the setState function, values will not 'scroll' on the right
render() {
return(
<input
name={this.props.input.Name}
type={this.props.input.Type}
defaultValue={this.state.value}
ref={this._input}
key={key()}
)}
The function that updates the Value is a common set Function :
public set Value(data: string) {
this.setState({
internalValue: data,
inputError: !this.validateValue(data)
});
}
Note that the input works as expected if i write from the Keyboard, but if i write the input using a 'simulated' keyboard on screen happens what i just described
Any ideas?
Thank you
Update after simbathesailor support:
render() {
return(
<input
name={this.props.input.Name}
type={this.props.input.Type}
defaultValue={this.state.value}
ref={this._input}
key={key()}
onChange={this.setValue}
/>
)
}
componentDidUpdate(prevProps: InputProps, prevState: InputState) {
if (prevState.value!== this.state.value) {
this._input.current.focus();
}
}
setValue(event: React.ChangeEvent<HTMLInputElement>) {
console.log('change');
this.setState({
value: event.target.value
})
}
shouldComponentUpdate(nextProps: InputProps, nextState: InputState): boolean {
return (this.state.value!= nextState.value);
}
public set Value(data: string) {
this.setState({
value: data,
inputError: !this.validateValue(data)
}, () => {
this._input.current.focus();
});
}
You can use the refs and commit lifecycle method componentDidUpdate method. to achieve this.
In the example mentioned below, it is done for the uncontrolled component. But idea will remain same for controlled component also.
class Test extends React.Component {
constructor(props) {
super(props)
this.InputRef = React.createRef()
this.state = {
value: 0
}
}
setValue = (event) => {
this.setState({
value:event.target.value
})
}
update = () => {
this.setState({
value: (this.state.value || 0) + 1000
})
}
componentDidUpdate(prevProps, prevState) {
if(prevState.value !== this.state.value) {
this.InputRef.current.focus()
}
}
render() {
return (
<div>
<input
value={this.state.value}
onChange={this.setValue}
ref={this.InputRef}
/>
<button onClick={this.update}>update</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById("root"))
Here is the codepen link to see it working:
Uncontrolled approach(javascript) codepen link
Controlled approach(javascript) codepen link
I have tried typescript for the first time. Thanks for your question :). Typescript is good. And here is your desired solution needed in typescript.
Codesandbox link(Typescript)

Resources