React JS - I don't Understand what is going on - javascript

In image it is saying It is expected to have ";", can someone explain ?
import React, {useReducer} from 'react';
import CartContext from './cart-context';
const defaultCartState = {
items : [],
totalAmount : 0
};
const cartReducer = (state, action) = {
if (action.type === 'ADD') {
const updatedItems = state.items.concat(item);
const updatedTotalAmount = state.totalAmount + action.item.price * action.item.amount;
return {
items : updatedItems,
totalAmount : updatedTotalAmount
};
}
return defaultCartState;
}
const CartProvider = (props) => {
const [cartState, dispatchCartState] = useReducer(cartReducer, defaultCartState);
const adder = (item) =>{
dispatchCartState({type : 'ADD', item : item})
};
const remover = (id) => {
dispatchCartState({type : 'REMOVE', id : id})
};
const cartContext = {
item: [],
totalAmount : 0,
addItem : adder,
removeItem : remover
}
return (
<CartContext.Provider value={cartContext}>
{props.children}
</CartContext.Provider>
);
}
export default CartProvider;
I don't know what code is saying. Picture has been attached.

You are Using the Arrow Function in a Wrong way
Update your cartReducer function like this
const cartReducer = (state, action) => {
if (action.type === 'ADD') {
const updatedItems = state.items.concat(item);
const updatedTotalAmount = state.totalAmount + action.item.price * action.item.amount;
return {
items : updatedItems,
totalAmount : updatedTotalAmount
};
}

Related

React project using

I'm building UI using React, where I am using redux for increment & decrement function. Unfortunately my increment and decrement buttons are not working, may be this issue is coming due to some logical error. I will be very grateful if anyone help me to solve this issue. Here I am posting my source code.
**Creating Redux store code**
import {createStore} from 'redux';
const initialState ={counter:0, showCounter: true};
const counterReducer = (state =initialState,action) => {
if (action.type === 'increment') {
state.counter++;
return {counter: state.counter + 1,
showCounter: state.showCounter
};
}
if (action.type === 'increase') return{
counter: state.counter + action.amount,
}
if ( action.type ==='decrement'){
return {
counter: state.counter - 1,
};
}
if (action.type === 'toggle'){
return{
showCounter: !state.showCounter,
counter: state.counter
};
}
return state;
};
const store = createStore(counterReducer);
export default store;
**Counte.js code**
import {useDispatch, useSelector} from 'react-redux';
import classes from './Counter.module.css';
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector(state => state.counter);
const show = useSelector(state => state.showCounter);
const incrementHandler = () => {
dispatch({type:'incremennt', amount:10});
};
const increaseHandler = () => {
dispatch({type:'decrement'});
};
const decrementHandler = () =>{
dispatch({type:'decremennt'});
};
const toggleCounterHandler = () => {
dispatch({type:'toggle'})
};
return (
<main className={classes.counter}>
<h1>Redux Counter</h1>
{show && <div className={classes.value}>{counter}</div>}
<div>
<button onClick={incrementHandler}>Increment</button>
<button onClick={increaseHandler}>Increase by 10</button>
<button onClick={decrementHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;
I hope this code can help you:
const counterReducer = (state = initialState, action) => {
if (action.type === 'increment') {
return {
...state,
counter: state.counter + 1
};
}
if (action.type === 'increase') {
return {
...state,
counter: state.counter + action.amount
};
}
if (action.type === 'decrement') {
return {
...state,
counter: state.counter - 1
};
}
if (action.type === 'toggle') {
return {
...state,
showCounter: !state.showCounter
};
}
return state;
};
After that, you should check the typo in the type of dispatch.
decremennt and incremennt.
Try this code:
const incrementHandler = () => {
dispatch({ type: 'increment', amount: 10 });
};
const increaseHandler = () => {
dispatch({ type: 'increase' });
};
const decrementHandler = () => {
dispatch({ type: 'decrement' });
};
const toggleCounterHandler = () => {
dispatch({ type: 'toggle' });
};

Push Array React Native Keep Replace And Not Append

What is the correct way to use push array in React native ?
const BuilderIndicatorCard = (props) => {
const [isChecked, setIsChecked] = useState(false);
const [checkedValue, setCheckedValue] = useState([]);
let storeCheckedValue = [];
useEffect(() => {
if (isChecked) {
storeCheckedValue.push(props.indicator);
}
console.log(storeCheckedValue);
}, [isChecked, checkedValue])
// const removeCheckedStrategy = (checkedValue, array) => {
// var copyArray = [...array];
// var index = copyArray.indexOf(checkedValue);
// if (index !== -1) {
// copyArray.splice(index, 1);
// setArray(copyArray);
// }
// }
return (
<CheckBox
containerStyle={styles.checkbox}
size={15}
textStyle={styles.name}
title={props.indicator}
checked={isChecked}
onPress={() => {setIsChecked(!isChecked)}}
/>
);
};
When I do storeCheckedValue.push(props.indicator); why the array keep replace and not append ?
This is show in the console :
Array [
"Price Below MA (5)",
]
Array [
"Price Below MA (7)",
]
Array [
"Price Below MA (9)",
]
did I miss something in here ?
I found a proper way to solve my question above.
This is how I did it.
I use redux-toolkit
Create a slice like :
import { createSlice } from '#reduxjs/toolkit'
const addChecked = (state, action) => {
state.indicator = [...state.indicator, action.payload];
}
const removeChecked = (state, action) => {
state.indicator = state.indicator.filter(data => data != action.payload);
}
// status: 'idle' | 'loading' | 'succeeded' | 'failed',
export const BuilderSlice = createSlice({
name: 'Builder',
initialState: {
indicator: [],
status: 'idle',
error: null
},
reducers: {
addCheckedIndicator: addChecked,
removeCheckedIndicator: removeChecked
},
extraReducers: {
}
});
export const { addCheckedIndicator, removeCheckedIndicator } = BuilderSlice.actions
Then In the card component I change to like this :
import { addCheckedIndicator, removeCheckedIndicator } from '../redux/slice/builder/BuilderSlice';
const BuilderIndicatorCard = (props) => {
const dispatch = useDispatch();
const data = useSelector(state => state.Builder.indicator);
const [isChecked, setIsChecked] = useState(true);
const addValue = useCallback(() => {
setIsChecked(!isChecked);
if (isChecked) {
dispatch(addCheckedIndicator(props.indicator));
} else {
dispatch(removeCheckedIndicator(props.indicator));
}
}, [isChecked]);
return (
<CheckBox
containerStyle={styles.checkbox}
size={15}
textStyle={styles.name}
title={props.indicator}
checked={props.checked}
onPress={() => {addValue()}}
/>
);
};
I dispatch the function in slice in here:
dispatch(addCheckedIndicator(props.indicator));
dispatch(removeCheckedIndicator(props.indicator));
And then make sure use :
const addValue = useCallback(() => {
},[second]);
Not useEffect.

Cart total is displaying NaN instead of total price

So the problem I am currently facing is this. I have a Cart logic located in the CartContext. Everything works except the total number of prices it is displaying NAN. Here is the link to the CodeSandbox for a better understanding https://codesandbox.io/s/frosty-sound-5y7pg?file=/src/CartItem.js:1486-1494
import React from "react";
function getCartFromLocalStorage() {
return localStorage.getItem("cart")
? JSON.parse(localStorage.getItem("cart"))
: [];
}
const CartContext = React.createContext();
function CartProvider({ children }) {
const [cart, setCart] = React.useState(getCartFromLocalStorage());
const [total, setTotal] = React.useState(0);
const [cartItems, setCartItems] = React.useState(0);
React.useEffect(() => {
localStorage.setItem("cart", JSON.stringify(cart));
let newTotal = cart.reduce((total, cartItem) => {
return (total += cartItem.amount * cartItem.price);
}, 0);
newTotal = parseFloat(newTotal.toFixed(2));
setTotal(newTotal);
// cart items
let newCartItems = cart.reduce((total, cartItem) => {
return (total += cartItem.amount);
}, 0);
setCartItems(newCartItems);
}, [cart]);
// global functions
const removeItem = id => {
setCart([...cart].filter(item => item.id !== id));
};
const increaseAmount = id => {
const newCart = [...cart].map(item => {
return item.id === id
? { ...item, amount: item.amount + 1 }
: { ...item };
});
setCart(newCart);
};
const decreaseAmount = (id, amount) => {
if (amount === 1) {
removeItem(id);
return;
} else {
const newCart = [...cart].map(item => {
return item.id === id
? { ...item, amount: item.amount - 1 }
: { ...item };
});
setCart(newCart);
}
};
const addToCart = book => {
const { id, image, by, bookName,RegularPrice } = book;
const item = [...cart].find(item => item.id === id);
if (item) {
increaseAmount(id);
return;
} else {
const newItem = { id, image, by, bookName, RegularPrice, amount: 1 };
const newCart = [...cart, newItem];
setCart(newCart);
}
};
const clearCart = () => {
setCart([]);
};
return (
<CartContext.Provider
value={{
cart,
cartItems,
total,
removeItem,
increaseAmount,
decreaseAmount,
addToCart,
clearCart
}}
>
{children}
</CartContext.Provider>
);
}
export { CartContext, CartProvider };
Your CodeSandbox link works fine for me. Total is not shown as NaN. The only problem: change the initial amount from 0 to 1 (CartContext.js, line 48):
cart.concat({
amount: 1,
/* ... */
})

How to store things in asyncstorage?

I'm having some problems setting up asyncstorage. example: if the user has switch to darkmode, darkmode should still be enabled when the user start the app again.
I'm also unsure if this is the right way of doing this.
any help is appreciated.--------------------------------------------------------------------------------
toggle.js
import * as React from "react";
import { Switch } from "react-native";
import { useTheme } from "../Data/ThemeContext";
import AsyncStorage from "#react-native-async-storage/async-storage";
export const Toggle = () => {
const { colors, setScheme, isDark } = useTheme();
const toggleScheme = () => {
isDark ? setScheme("light") : setScheme("dark");
setScheme(isDark);
storeSetScheme(isDark);
};
React.useEffect(() => {
restoreDarkModeAsync();
}, []);
const asyncStorageKey = "#key";
const storeSetScheme = (isDark) => {
const stringifiedIsDark = JSON.stringify(isDark);
AsyncStorage.setItem(asyncStorageKey, stringifiedIsDark).catch((err) => {
console.log(err);
});
};
const restoreDarkModeAsync = () => {
AsyncStorage.getItem(asyncStorageKey)
.then((stringifiedIsDark) => {
const parsedTodos = JSON.parse(stringifiedIsDark);
if (!parsedTodos || typeof parsedTodos !== "object") return;
setScheme(parsedTodos);
})
.catch((err) => {
console.warn(err);
});
};
return (
<Switch
value={isDark}
onValueChange={toggleScheme}
thumbColor={colors.text}
trackColor={{ true: colors.text, false: colors.text }}
/>
);
};
ThemeContext.js
import * as React from "react";
import { useColorScheme } from "react-native-appearance";
import { lightColors, darkColors } from "../Theme/colorThemes";
export const ThemeContext = React.createContext({
isDark: false,
colors: lightColors,
setScheme: () => {},
});
export const ThemeProvider = (props) => {
const colorScheme = useColorScheme();
const [isDark, setIsDark] = React.useState(colorScheme === "dark");
React.useEffect(() => {
setIsDark(colorScheme === "dark");
}, [colorScheme]);
const defaultTheme = {
isDark,
colors: isDark ? darkColors : lightColors,
setScheme: (scheme) => setIsDark(scheme === "dark"),
};
return (
<ThemeContext.Provider value={defaultTheme}>
{props.children}
</ThemeContext.Provider>
);
};
export const useTheme = () => React.useContext(ThemeContext);
useColorScheme() returns string or null. But you have next check in restoreDarkModeAsync
if (!parsedTodos || typeof parsedTodos !== "object") return;
that's why it fails.
And here is more correct and clean way to toggle scheme
const toggleScheme = () => {
const nextScheme = isDark ? "light" : "dark";
setScheme(nextScheme);
storeSetScheme(nextScheme);
};

How do I access specific items in an object of arrays in reducers

I want to toggle an item's completed property by with clicking. The problem is I have no idea how to do this within reducer state. The property is stored inside an object of arrays which makes it tricky to locate in reducer.
App.js
import React,{ useReducer,useState } from 'react';
import logo from './logo.svg';
import './App.css';
import {reducer, initialState} from "./reducers/reducer"
function App() {
const [item,setItem] = useState("")
const [state,dispatch] = useReducer(reducer,initialState)
const handleCompleted = () => {
dispatch({type:"TOGGLE_COMPLETED",payload:0})
console.log(state[0])
}
const handleChanges = e => {
setItem(e.target.value)
}
const addTodo = e => {
dispatch({type:"ADD_TODO",newItem:{item:item,id:Date.now(),completed:false}})
e.preventDefault()
console.log(state)
}
return (
<form onSubmit={addTodo}>
<button>submitTodo</button>
<input onChange={handleChanges} value={item} />
<div>
<button onClick={handleCompleted}>completed</button>
{state.list.map(i => <p key ={i.id}>{i.item}</p>)}
</div>
</form>
);
}
export default App;
Reducer.js
export const initialState = {
list :[{item: 'Learn about reducers',
completed: false,
id: 3892987589}]
}
export const reducer = (state,action) => {
switch(action.type){
case "TOGGLE_COMPLETED" :
return state.list[action.payload].completed = !state.list[action.payload].completed
case "ADD_TODO" :
return {...state,list:[...state.list,action.newItem]}
default:
return state}
}
you can use findIndex. In your case use the id to find the index in the array then change the status of completed
const initialState = {
list: [{
item: 'Learn about reducers',
completed: false,
id: 3892987589
}]
}
function changeStatus(id) {
let getIndex = initialState.list.findIndex(e => e.id === id);
initialState.list[getIndex].completed = true;
}
changeStatus(3892987589);
console.log(initialState.list)
You can modify the function as follows in your App.js
const handleCompleted = (id) => {
dispatch({type:"TOGGLE_COMPLETED",payload:id})
}
In the render function
change <button onClick={handleCompleted}>completed</button> to
{state.list.map(i => <p key ={i.id}>{i.item}<button onClick={this.handleCompleted.bind(this, i,id)}>completed</button></p>)}<button onClick={this.handleCompleted.bind(this, id)}>completed</button>
And in Reducers.js
Note: Usually, you would create a map of ids corresponding to the items for ease of updates. But this would also work for now.
export const reducer = (state,action) => {
switch(action.type){
case "TOGGLE_COMPLETED" :
const modifiedState = state.map(item=> {
if(item.id === action.payload.id){
return {
...item,
completed: true
}
}
return item
});
return modifiedState
case "ADD_TODO" :
return {...state,list:[...state.list,action.newItem]}
default:
return state}
}

Categories

Resources