How to assign first state data to second state in react? - javascript

When i am setting the data from one state to another state. It's saying undefined. Currently i am working on tinder like card swipe functionality with Right and left button click.
I am passing the user id from card to to button. Such as Right swipe and left swipe button.
//Scenario first
If have declared the array of object static, it's works like a charm, then it does not says any error.
////Scenario Second
If i am setting the data dynamically with API to SetState and assigning the state variable array data to another state variable, it says undefined.
I am trying to solve this issue from 3 days, but nothing worked, i am new in React js. Help would be appreciate.
Here is my code
const AllData= [
{
id: 1,
name: 'XYZ'
},
{
id: 2,
name: 'ABC'
},
{
id: 3,
name: 'ABC 2'
},
{
id: 4,
name: 'ABC 3'
},
{
id: 5,
name: 'ABC 4'
}
] //It works if set static array
const [AllData, setAllData] = useState([]); //it does not works
const GetAllUserData = async () =>{
const bodyParameters ={
session_id : SessionId
};
const {data : {data}} = await axios.post(GETALLUSER_API , bodyParameters);
setAllData(data);
}
// Setting current user from all data
const [currentUser, setCurrentUser] = useState(AllData[0])
console.log(currentUser); // undefined says

Here, AllData will be added to the state after the GetAllUserData is done executing, it is asynchronous function, so AllData will be available after some time, you have to update the currentUser you have to do like this.
useEffect(() => {
if (AllData.length) {
setCurrentUser(AllData[0]);
}
}, [AllData]);

It didn't worked because you may have returned before the setAllData could get called initialize AllData.
Being a api call it take some time to return data.
A good work around for this situation is to put a loader until it get the data and when you eventually receive the data then only render the content on the screen.

Related

How can I make an object stored in localstorage be null when an event happens but return to it's original form after the inverse event?

Data has this format:
{
"id": 1,
"current_tenant_id": 8,
"main_tenant_id": 6,
"employee": {
"id": 1021,
...}
}
I have this other code:
const handleChange = () => (event) => {
const localUser = getItemFromLocalStorage(LOCAL_STORAGE_NAMES.user);
if (!isMainTenantEqualToCurrentTenant(localUser)) {
localUser.employee = null
}
setInLocalStorageAsync(LOCAL_STORAGE_NAMES.user, localUser);
...
This works fine: after changing the tenant, it sets employee to null in localstorage. However, what I actually want, is to set user.employee to null when main tenant is not equal to the current tenant, but also to re-set the initial user.employee when the change causes the current and main tenant to be equal again, ideally without making another call to the backend (handling everything in the frontend). How can I accomplish this?

What is the right way to store a object in React

I want to store my Object of my Checkout-Cart in a React Variable.
I tried it with the useState Component but that did not work.
This is my object which I get from my NodeJs Backend :
`
[
{
product_uuid: '3bef830f-a06d-4562-8793-bb94f725226a',
product_quantity: 1,
product_name: 'Example Product',
product_price: 30,
product_img: ''
}
]
And this is my code on how to store it:
var cart=[{}];
useEffect(() => {
Axios.post("http://localhost:3001/products/getCart", {
}).then((response) => {
if(response.data.error){
}else{
cart = response.data.finished_cart;
console.log(response.data.finished_cart)
}
console.log(cart)
});
}, []);
When i log the cart in this part of the code everything works fine and I get my Object stored but when i want to access it in the jsx part it is undefined:
return (
<div>
{console.log(cart)}
</div>
)
I also tried to store the cart with this method but this does not work:
//Method 1
const[cart,setCart]=useState([{}]);
//Method 2
const[cart,setCart]=useState([{product_uuid:0,product_quantity:0,product_name:"",product_price:0,product_img:""}]);
The useState direction is the way to go. After you get your cart result back you should use the setCart function to update your state, which will re-render your component with the new cart value
setCart(response.data.finished_cart);

mutate in useSWR hook not updating the DOM

It's a next.js app and I populate the data using a useSWR hook.
const { data, error } = useSWR('/api/digest', fetcher, {
revalidateOnFocus: false,
})
The issue is that the DOM doesn't get updated as expected after the mutate() line below. But if I hard code the data as updatedData and pass it as the arg for the mutate it works normally. The fact is that data and the updatedData are the same. See comments below.
Edit: If I click on any Navbar <Link/> it gets updated.
Any clues of what is happening?
const handleAddRowClick = async () => {
const newRow = { category: selectedCategory, entity: selectedEntity }
data.subscription[selectedCategory].push(selectedEntity);
console.log(data); // This data is equal to updatedData
const updatedData = {
"subscription": {
"materialFact": [
"Boeing"
],
"headlines": [
"thejournal",
"onemagazine" // ***This is the value added.
]
}
}
// mutate('/api/digest', data, false) // This does not works.
mutate('/api/digest', updatedData , false) // It works.
}
I am assuming that the data property you use in handleAddRowClick is the same that you get from useSWR. Now, if you update some deeply nested object in data, it doesn't change the data reference. It still points to the old object. So, if you pass it again to mutate, for mutate, the object is still the same and hence, it won't trigger a re-render.
I would recommend that you do something like the following to derive updatedData from data and then pass it to the mutate function.
const handleAddRowClick = async () => {
const updatedData = {
...data,
subscription: {
...data.subscription,
[selectedCategory]: [
...data.subscription[selectedCategory],
selectedEntity,
]
}
}
mutate('/api/digest', updatedData , false);
}
On a side note, you can also use something like immer to simplify copying the state.

set an array with useState doesn't change the result

I have a list of data like this:
data = [
{
id:1,
name: "boo"
},
{
id:1,
name: "boo"
}
]
I initialize it with react UseState like follows:
const [items, setItems] = useState(data)
And I map this in my react code and visualize them.
If I want to delete one I do it with the following function:
const deleteItem = async (id) => {
console.log('BEFORE- - - ->', items);
// this functions calls an api to delete the item
await deleteItem({ id });
setItems((oldItems) =>
oldItems.filter(({ id }) => id !== commentId)
);
console.log('AFTER- - - ->', items);
};
Graphically the component with the deleted item disappears, but actually the second console.log prints the same thing as the first log. In this case if I delete the element with id:1 I will get the same log while I see graphically that the element disappears. This causes a problem with indexing if I want to delete more than one item.
Which do you think is the problem? has I to do it into one useEffect?
Setting state is an asynchronous action. If you put a console outside of that function, on the next re-render you will see your state updated correctly (just like you've seen your item disappear visually).
This happens because setState is asynchronous so the state really changes after you console.log

Weird destructuring behavior in React

I have a deeply nested JSON object as state initially made with useState hook -
const [template, setTemplate] = useState([
{
statement: 'this is top level statement',
nestingLevel: 0,
children: [
{
nestingLevel: 1,
statement:
'this is a statement with such a template',
children: [
{
statement: 'first chart',
nestingLevel: 2,
},
{ statement: 'second chart',
nestingLevel: 2,
},
],
},
],
},
{
statement:
'this is second statement for section with such a metric {{}}',
nestingLevel: 0,
},
]);
I have an input element with an onChange handler.
As you can see, whenever there is some change in the input text, I update some relevant key-value pair based on path. I do so by using the lodash library's get and set functions.
const handleDataChange = (e, path) => {
console.log('handling the data');
// copy the template
let templateCopy = template;
// create the new object with updated information
const tempObj = _.set(
templateCopy,
`${path}['statement']`,
e.target.value,
);
setTemplate([...tempObj]);
};
The problem is in the handleDataChange function. When I do setTemplate(tempObj) the state doesn't get updated. However when I do setTemplate([...tempObj])(which will essentially yield the same result), this later solution works as expected.
I want to know why that is the case. Is it because lodash gives results always as object and destructuring and repacking it make it array again and hence it works as expected?
The object reference stays the same when you mutate nested property only, and as react does shallow comparison in order to detect changes, it won't react to the change.
You can deepClone the object, then mutate it as you do with set and then update the state.

Categories

Resources