changing object values with onchange handler with react hooks - reactjs

I have onChange handler but when I type it removes the lng value from the whole object
So I have an object stored in State.
const [inputFields, setInputFields] = useState({
style: "",
coordinates: { lat: 51.501476, lng: -0.140634 },
assetId: "",
});
The onChange handler
const handleLat = (event) => {
setInputFields({ ...inputFields, coordinates: {[event.target.name]: parseInt(event.target.value)} })
};
Which results in
{
"style": "",
"coordinates": {
"lat": 23434434287
},
"assetId": ""
}
I would like to retain the "lng" value and not override the whole coordinates object.

Following above thread, You can do this:
setInputFields(inputFields => ({ ...inputFields, coordinates: {...inputFields.coordinates,[event.target.name]: parseInt(event.target.value)} }))

try following :
const handleLat = (event) => {
setInputFields(
{ ...inputFields,
coordinates: {[event.target.name]: parseInt(event.target.value), ...inputFields.coordinates}
})
};

Related

Update a specific objects values in an array of objects redux

My goal is to update the animatedPhotoUrl value for chatId #1 (or the first object in the chats array.
const chats = [
{"admin": "590",
"animatedPhotoUrl": "",
"chatId": "1"},
{"admin": "680",
"animatedPhotoUrl": "",
"chatId": "2"},
{"admin": "420",
"animatedPhotoUrl": "",
"chatId": "2"}
]
However, when I console.log(chats) after I update in the reducer, I get the error:
[undefined, undefined]
Here is my dispatch:
dispatch({
type: "UPDATE_CHAT_PROFILE_PICTURE_URL",
payload: {
profilePictureUrl: res.imageUrl,
animatedPhotoUrl: "",
chatId: chat.chatId,
},
});
And here is the code in my reducer:
case "UPDATE_CHAT_PROFILE_PICTURE_URL":
return {
...state,
chats: state.chats.map((chat) => {
chat.chatId === action.payload.chatId
? {
...chat,
animatedPhotoUrl: action.payload.animatedPhotoUrl,
}
: chat;
}),
};
You need to add return here:
chats: state.chats.map((chat) => {
return chat.chatId === action.payload.chatId
? {
...chat,
animatedPhotoUrl: action.payload.animatedPhotoUrl,
}
: chat;
}),
or you need to drop braces to get implicit return:
chats: state.chats.map((chat) =>
chat.chatId === action.payload.chatId
? {
...chat,
animatedPhotoUrl: action.payload.animatedPhotoUrl,
}
: chat;
),

React does not update nested state using my setter

I'd like to update a react state (the "app" variable) object dynamically. The state has several properties, one of them is a nested object ("app.error" object). There is a kind of setter function ("setAppData") which takes any number of [existing key]: new value pairs of the state as parameter, create a new object and it should update the state according to "temp" object.
It works as intended when I want to update "app.error" using hard-coded variable or any other "app" properties, when I try to update the "app.error" using my setter function, it does not update.
const initialAppData: IAppData = {
error: {} as IFrontEndError,
interfaceTheme: UI_THEME.LIGHT,
};
function AppProvider(props: any) {
const [app, setApp] = useState<IAppData>(initialAppData);
useMemo(() => {
window.addEventListener("error", (event) => {
errorHandler({
colno: event.colno,
filename: event.filename,
lineno: event.lineno,
message: event.message,
});
});
}, []);
const errorHandler = (event: IFrontEndError) => setAppData({error: { ...event }});
const setAppData = (newValue: TUpdateAppData) => {
let key: keyof IAppData;
let temp = getAppData();
for (key in newValue) {
if (
!Object.prototype.hasOwnProperty.call(app, key) ||
!Object.prototype.hasOwnProperty.call(newValue, key)
)
continue;
temp = {
...temp,
[key]: newValue[key],
};
}
setApp({ ...temp, error: { ...temp.error } });
};
const getAppData = () => ({ ...app });
}
Using static update (it works as intended):
const setAppData = () => {
let temp = getAppData();
temp.error = {
colno: 1,
lineno: 1,
message: "asd",
filename: "asd"
}
setApp({ ...temp, error: { ...temp.error } });
};
The structure of the "temp" objects before passing the spreaded copy to the state setter are exactly the same. "temp" object before spreading, triggered by event:
{
"error": {
"colno": 11,
"filename": "http://127.0.0.1:5173/src/components/Debug.tsx?t=1667134926865",
"lineno": 29,
"message": "Error: asd"
},
"interfaceTheme": "light-theme"
}
getAppData() after error event:
{
"error": {},
"interfaceTheme": "light-theme"
}
"temp" object before spreading using hard-coded value:
{
"error": {
"colno": 1,
"lineno": 1,
"message": "asd",
"filename": "asd"
},
"interfaceTheme": "light-theme"
}
getAppData() after execution using hard-coded value:
{
"error": {
"colno": 1,
"lineno": 1,
"message": "asd",
"filename": "asd"
},
"interfaceTheme": "light-theme"
}
What is that I don't notice?
edit: sources of the project:
https://github.com/gazsop/magus_shared
https://github.com/gazsop/magus_react

updating specific objects of array in reactjs

i want update only specific object from default _data i.e (isconformed value to 1) when user click confirm button that should object isconformed value to 1 and api put call to set the change value in data?
const default_data = {
Id: "",
productname: "",
price:"",
isconformed:0,
}
const[data,setData]=useState(default_data)
const OnChangeHandler = (key, value) => {
//console.log(value) i.e value will be 1 here
setData({ ...data, [key]: value });
};
const Confirmproduct = () => {
const res_data = {
isConformed: data.isConfirmed,
};
//API call
axios.put(`${config.APP_CONFIG}/Product/${Id}`, res_data)
.then((res) => {
setdata(res.data)
})
}
onClick={(e) => {
//when button clicked
e.preventDefault();
OnChangeHandler("isConformed", 1);
Confirmproduct()
}}
}
My expected output
{
Id: "",
productname: "",
price:"",
isconformed:1,
}
The setData function is an asynchronous hook which, when called, does not update immediately the value of data as, for example, using default_data["isconfirmed"]=value.
My recommendation is to simplify and remove the handle function as you don't need it
const default_data = {
Id: "",
productname: "",
price:"",
isconformed:0,
}
const[data,setdata]=useState(default_data)
const Confirmproduct = (key, value) => {
// setData({ ...data, [key]: value }); <- Do you really need this?
const res_data = {
isConformed: value
};
//API call
axios.put(`${config.APP_CONFIG}/Product/${Id}, res_data)
.then((res) => {
setdata(res.data)
})
** button click event**
onClick={(e) => {
e.preventDefault();
Confirmproduct("isConformed", 1);
}}

How to change data of children with useState?

const [blocks, setBlocks] = useState({
"time": null,
"blocks": [
{
"key": 1,
"data": "This is some data"
}
]
});
How can I use setBlocks to change "data" to "this is some other data"?
set method of useState not only accepts data, but also accepts functions.
setState(prevState => {
return {...prevState, ...updatedValues};
});
So you can write something like this.
setBlocks(prevState => ({
...prevState,
blocks: prevState.blocks.map(v => {
return (v.key === 1)
? {...v, data: 'this is some other data'}
: v;
}),
});

Update Nested state in react

Hello guys I'm trying to update the state of a nested object in react, I'm currently doing this:
handleChange({target: {id, value}}, type) {
this.setState(
state => ({
dwelling: (Object.assign(state.dwelling, {[id]: {[type]: value}}))
})
);
}
it comes from a formgroup:
<FormGroup controlId="spaces">
<ControlLabel>Dormitorios</ControlLabel>
<FormControl
componentClass="select"
value={dwelling.spaces.dorms}
placeholder="Seleccione"
onChange={e => this.handleChange(e, 'dorms')}
>
The problem is when I update the state of the sub object dwelling.spaces.dorms is created but when I try to place another property it replaces the old one instead of getting added:
Before Dwelling:
{
address: "",
currency: "",
price: 0,
publicationType: "",
spaces: {
closets: "",
dorms: "",
pools: ""
},
subtype: "",
type: ""
}
After onChange for dwelling.spaces.dorms
{
address: "",
currency: "",
price: 0,
publicationType: "",
spaces: {
dorms: "3",
},
subtype: "",
type: ""
}
After onChange for dwelling.spaces.closets
{
address: "",
currency: "",
price: 0,
publicationType: "",
spaces: {
closets: "3",
},
subtype: "",
type: ""
}
This example uses ES6 spread operator to keep your old properties which is the equivalent of Object.assign.
So what was happening is you're not keeping your nested value.
this.setState({
dwelling: {
...this.state.dwelling,
[id]: {
...this.state.dwelling[id],
[type]: value
}
}
});
In your example you overwrote your value with a new object. Notice the bolded text below.
dwelling: (Object.assign(state.dwelling, {[id]: {[type]: value}}))
In the bolded text it specifically set a new object into state.dwelling without keeping the old values. So what we did is that we used the ES6 spread operator to help merge your old values with the new value
{
...this.state.dwelling[id],
[type]: value
}
I keep my form state in a complex object and to simplify my code I use this helper function in my "handleChange" function referenced by TextField, Select, etc..
export function updateObject(obj, keys, value) {
let key = keys.shift();
if (keys.length > 0) {
let tmp = updateObject(obj[key], keys, value);
return {...obj, [key]: tmp};
} else {
return {...obj, [key]: value};
}
}
React-redux/Material-UI example
let [formState, changeFormState] = useState({});
function handleChange(event) {
changeFormState(updateObject(formState, event.target.name.split('.'),
event.target.value));
}
<TextField className={classes.textfield} name='foo.bar' value=
formstate.foo.bar || ''} onChange={handleChange} />

Resources