What is the right way to store a object in React - javascript

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);

Related

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.

Merging existing localstorage item with state for a shoppingcart

I got a situation where I do not have the experience to know which method is the best and what im doing wrong. The situation is as following:
I got a page with products which have a input + order button, which will add the order to the shoppingcart. My thought was to first set the state for each order you make:
const [amountItem, setAmountItem] = useState({
product: {
id: '',
amount: ''
}
});
Updating:
function handleChange(evt, id) {
const value = evt.currentTarget.value;
setAmountItem({
...amountItem,
product:{
id: id,
amount: value
}
});
console.log(amountItem);
}
Which then I push to the shoppingcart/checkout page (no modal):
if (e.target[0].value < productItem.stock) {
history.push({
pathname: `/winkelwagen/`,
state: {data: amountItem}
});
On this page, i first check if location.state exists before using the shoppingcart component:
if (location.state !== null && shoppingCartItems === '') {
console.log(location.state.data);
setShoppingCartItems(location.state.data);
setShoppingCartActive(true);
let cartString = JSON.stringify(shoppingCartItems);
localStorage.setItem('shopping_carts', cartString)
}
When it does exist, some product is ordered with an amount and must be set to localstorage, the product is 'always' visible when refreshing, etc. Until this point it works, the localstorage item exists:
(key)shopping_carts (value){"product":{"id":3,"amount":"2"}}
After that comes the shoppingcart component:
<ShoppingCart
shoppingCartItems={shoppingCartItems}
setShoppingCartItems={setShoppingCartItems}
shoppingCartActive={shoppingCartActive}
setShoppingCartActive={setShoppingCartActive}
/>
This is where my problem starts. Long story short, it only shows the single item from the state, which obviously will be gone.
In this file I got a useEffect part for the localstorage:
useEffect(() =>{
let shoppingCart = localStorage.getItem("shopping_carts");
console.log('shoppingcartitems ');
shoppingCart = JSON.parse(shoppingCart);
console.log(shoppingCart);
if (shoppingCart !== "") {
const id = shoppingCartItems.id;
const amount = shoppingCartItems.amount;
//setShoppingCartItems(shoppingCart)
setShoppingCartItems(prevState => ({
...prevState,
product: {
...shoppingCartItems,
id: id,
amount: amount
}
}))
}
}, [setShoppingCartItems])
The output for 'shoppingCart' is <empty string>. Why is that? Is the format wrong? I'm also using the localstorage for other info, which works fine. I know the setShoppingCartItems is not correct for multiple values, but I wanted to test this single entry first.
Update:
const CheckoutPage = () => {
const location = useLocation();
const [shoppingCartItems, setShoppingCartItems] = useState('');
const [shoppingCartActive, setShoppingCartActive] = useState(false);
const [mode, setMode] = useState('init');
let savedShoppingCart = JSON.parse(localStorage.getItem("shopping_carts"));
console.log('saved shopping cart: ')
console.log(savedShoppingCart);
if (savedShoppingCart !== "" && mode === 'init') {
const id = savedShoppingCart.id;
const amount = savedShoppingCart.amount;
//setShoppingCartItems(shoppingCart)
setShoppingCartItems(prevState => ({
...prevState,
product: {
...shoppingCartItems,
id: id,
amount: amount
}
}))
setMode('data');
//setShoppingCartActive(true);
}
if (location.state !== null && shoppingCartItems === '') {
console.log(location.state.data);
setShoppingCartItems(location.state.data);
setShoppingCartActive(true);
let cartString = JSON.stringify(shoppingCartItems);
localStorage.setItem('shopping_carts', cartString)
}
return (
<div className="shoppingCartPage">
<ShoppingCart
shoppingCartItems={shoppingCartItems}
setShoppingCartItems={setShoppingCartItems}
shoppingCartActive={shoppingCartActive}
setShoppingCartActive={setShoppingCartActive}
/>
</div>
)
}
So basically I want to do 3 things here:
Get the data from the localstorage item
Is there a saved localstorage item? Add it to existing shoppingCartItems (prevstate)
Save the updated (or new when no localstorage item exists) shoppingCartItems after that
After that I want to pass the data to the shoppingcart where i can increase/decrease items or remove/splice the values.
Treat useEffect with caution as an eventListener on React state.
Therefore you need to specify in the dependency array everything might change, in order to trigger the useEffect callback.
In your useEffect dependencies, where you are updating your shoppingCartItems, you have added only setShoppingCartItems - which I assume that its a setState function. This results in your useEffect te be called only once at the app start because setState functions never change.
So, to have your shoppingCartItems updated via useEffect you need to add it to dependencies.
useEffect(() => {
// your code
}, [setShoppingCartItems, shoppingCartItems])
This may fix your problem, because you never call logic that saves update shopping cart state, the second time, therefore you get empty in your console log.

Object items are not rendering (Object is stored in an array of objects which in turn is stored in a React state hook)

My problem is that item stored in object (in an array of objects inside a state hook) is not being rendered on page, but it gets printed with console.log
I fetched some data from the server and it worked as expected, returning an array of two items, one of which is an object containing blog data(blog heading, creator, etc) an another is an array of 'sections' of that blog. Here is how I did it,
This is the initialization
// Get the blog id
const {blog_id} = useParams();
// Declaring our state hooks
const initial_blog_state = {
blog_id: blog_id,
heading: '',
creator: {},
created: '',
section: [],
}
const [blog_state, updateBlogState] = useState(initial_blog_state);
Here is the fetching of data from the server
useEffect(() => {
// Fetching data
Promise.all([
fetch(`http://127.0.0.1:8000/api/blog/${blog_id}`),
fetch(`http://127.0.0.1:8000/api/section/full/${blog_id}`)
]).then(responses => {
// Get a JSON object from each of the responses
return Promise.all(responses.map(response => {
return response.json()
}))
}).then(function (data) {
// Log the data to the console
console.log(data);
// Update state
updateBlogState({
...blog_state,
heading: data[0].heading,
creator: data[0].creator,
created: data[0].created,
section: data[1]
})
}).catch(function (error) {
// if there's an error, log it
console.log(error);
});
}, []);
I think the way I'm updating the section inside the hook can be a problem(although I'm not sure how), because I saw in a stackoverflow answer that objects must always be initialized (which I'm not doing when declaring an array of 'objects')
And here is the thing that needs to be rendered
return (
<div className="container">
<h1>{blog_state.heading}</h1>
<p className="text-small text-muted">{blog_state.creator.username}</p>
{blog_state.section.map(item => {
{console.log(item.paragraph)}
<p>{item.paragraph}</p>
})}
</div>
)
Here blog_state.heaing and blog_state.creator.username are being rendered as desired and also console.log(item.paragraph) prints the correct paragraph on the console window, but item.paragraph doesn't show anything on the page.
Nothing is being returned from your map.
i.e you need to add a return line before the <p>{item.paragraph}</p>
So:
{blog_state.section.map(item => {
console.log(item.paragraph)
return <p>{item.paragraph}</p>
})}
or as an inline return:
{blog_state.section.map(item => <p>{item.paragraph}</p>)}

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

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.

Updating state for a value inside an object immutably in redux reducers

I want to update a state value where the key is also dynamic in redux reducer, but I tried various method I am not able to do it.
So my Initial State looks like this
const initalState = {
ingredients:{
bacon:0,
salad:0,
cheese:0,
meat:0,
},
price:100
};
And my data passed in reducer looks like this
{type: "INCREASEQUANTITY", payload: {
item: "bacon",
value: 1
}}
And I want result state looks like
const initalState = {
ingredients:{
bacon:1, //updated value
salad:0,
cheese:0,
meat:0,
},
price:100
};
I tried to update it immutably, but its showing syntax error.
My code for this looks like this
return{
...state,
state.ingredients:{
...state.ingredients,
action.payload.item:state.ingredients[action.payload.item]+action.payload.value //this line explained below
}
}
I want to update it with key and value both dynamically like bacon:0+1 but getting syntax issue.
Please help.Thank you
You were on the right track
return {
...state,
ingridients: {
...state.ingridients,
[action.payload.item]: state.ingredients[action.payload.item] + action.payload.value
}
}

Categories

Resources