React Redux, trying to add products to cart - javascript

I am trying to add products to shopping cart by storing them in local storage but, they are not getting stored. I looked into Redux-dev-tools and found out my state is not updating:
As you can see action is getting fired but my state is not updating:
Here is the source code:
cartAction.js
import axios from "axios"; import { CART_ADD_ITEM, CART_REMOVE_ITEM } from "../constants/cartConstants";
export const addToCart = (id, qty) => async (dispatch, getState) => { const { data } = await axios.get(`/api/product/${id}`);
dispatch({
type: CART_ADD_ITEM,
payload: {
productID: data.product._id,
name: data.product.name,
image: data.product.image,
price: data.product.price,
countInStock: data.product.countInStock,
qty,
}, });
localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems)); };
cartReducer.js
import { CART_ADD_ITEM, CART_REMOVE_ITEM } from "../constants/cartConstants";
export const cartReducer = (state = { cartItems: [] }, action) => {
switch (action.state) {
case CART_ADD_ITEM:
const item = action.payload;
const existItem = state.cartItems.find(
(x) => x.productID === item.productID
);
if (existItem) {
return {
...state,
cartItems: state.cartItems.map((x) =>
x.productID === existItem.productID ? item : x
),
};
} else {
return {
...state,
cartItems: [...state.cartItems, item],
};
}
// case CART_REMOVE_ITEM:
// return {};
default:
return state;
}
};
store.js
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
// reducers
import {
productDetailsReducer,
productListReducer,
} from "./reducers/productReducers";
import { cartReducer } from "./reducers/cartReducers";
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
cart: cartReducer,
});
const cartItemsFromStorage = localStorage.getItem("cartItems")
? JSON.parse(localStorage.getItem("cartItems"))
: [];
const initialState = {
cart: { cartItems: cartItemsFromStorage },
};
const middleware = [thunk];
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
CartScreen.js
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addToCart, removeFromCart } from "../../redux/actions/cartActions";
import { Link } from "react-router-dom";
import ErrorMessage from "../../components/ErrorMessage/ErrorMessage";
import "./CartScreen.scss";
const CartScreen = ({ match, location, history }) => {
const productID = match.params.id;
const qty = location.search ? Number(location.search.split("=")[1]) : 1;
const dispatch = useDispatch();
const cart = useSelector((state) => state.cart);
const { cartItems } = cart;
console.log(cartItems);
useEffect(() => {
if (productID) {
dispatch(addToCart(productID, qty));
}
}, [dispatch, productID, qty]);
return (
<>
<h1>Shopping Cart</h1>
</>
);
};
export default CartScreen;

You need to fix this on CartReducer.js
switch (action.state) {
to
switch (action.type) {

Related

React Redux not displaying the data when trying to dispatch (Firestore)

I'm trying to use React Redux on my application. I will be building something like instagram, so the scale of the application is going to be big. I have implement redux correctly (I believe) although I'm not getting the fetch result from firestore on the dispatch function, if I insert the same code before the return it works.
action/index.ts:
import { db, auth } from '../../services/firebase';
import { USER_STATE_CHANGE } from '../constants';
export function fetchUser() {
return (dispatch: any) => {
db.collection('users')
.doc(auth.currentUser!.uid)
.get()
.then((snapshot) => {
if (snapshot.exists) {
console.log(snapshot)
dispatch({
type: USER_STATE_CHANGE,
payload: snapshot.data(),
});
}
});
};
}
constants/index.ts:
export const USER_STATE_CHANGE = 'USER_STATE_CHANGE';
reducers/index.ts:
import { combineReducers } from 'redux';
import { user } from './user';
const Reducers = combineReducers({
userState: user,
});
export default Reducers;
reducers/user.ts:
const initialState = {
currentUser: null,
};
export const user = (state = initialState, action: any) => {
return {
...state,
currentUser: action.currentUser,
};
};
App.tsx:
// Redux
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './src/redux/reducers';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk));
export default function App() {
if (!fontsLoaded) return <></>;
return (
<ThemeProvider theme={theme}>
<Provider store={store}>
<Main />
</Provider>
<ToastMessage />
</ThemeProvider>
);
}
Main.tsx:
import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { AuthRoutes } from './routes/auth.routes';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchUser } from './redux/actions';
import { auth } from './services/firebase';
function Main() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
fetchUser();
auth.onAuthStateChanged((user) => {
if (user) setIsAuthenticated(true);
});
}, []);
return (
<NavigationContainer>
<AuthRoutes isAuthenticated={isAuthenticated} setIsAuthenticated={setIsAuthenticated} />
<StatusBar style="auto" />
</NavigationContainer>
);
}
const mapDispatchProps = (dispatch: any) => bindActionCreators({ fetchUser }, dispatch);
export default connect(null, mapDispatchProps)(Main);
The fetchUser() is called here, and should log the data from firestore, although I don't get any data logged.
The function is beeing called:
on reducer/user.ts
Have you try to do this:
const initialState = {
currentUser: null,
};
export const user = (state = initialState, action: any) => {
return {
...state,
currentUser: action.payload,
};
};
Replace this
export const user = (state = initialState, action: any) => {
return {
...state,
currentUser: action.currentUser,
};
};
With this
export const user = (state = initialState, action: any) => {
return {
...state,
currentUser: action.payload,
};
};
Because you are setting data in payload but you are accessing from currentUser which empty. Either replace payload with currentUser in useDispatch or replace currentUser with payload in reducer.

useSelector Returning Undefined object

I am trying to store users fetched by random users api and trying to dispatch it to my store i have store users with an empty array, when i am trying to get users using useSelector i am getting an undefined object.
Here is my store.js:
import { configureStore } from "#reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
import userReducer from "../features/users/userSlice";
export const store = configureStore({
reducer: {
counter: counterReducer,
user: userReducer,
},
});
Here is userSlice.js
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "users",
initialState: {
userArray: [],
},
reducers: {
getUsers: (state, action) => {
state.userArray = action.payload;
}
}
})
export const { getUsers } = userSlice.actions;
export const selectUsers = (state) => state.users.userArray;
export default userSlice.reducer;
Here is App.js
import logo from './logo.svg';
import './App.css';
import {useSelector, useDispatch } from 'react-redux';
import { getUsers, selectUsers } from './features/users/userSlice';
function App() {
const dispatch = useDispatch();
const users = useSelector(selectUsers);
const fetchUsers = async () => {
fetch("https://gorest.co.in/public/v2/users")
.then((response) => response.json())
.then((data) => {
console.log("data=====", data);
dispatch(getUsers(data));
});
};
return (
<div className="App">
<header className="App-header">
<button onClick={fetchUsers}>Get Users</button>
{users.length > 0 &&
users.map((user) => {
<li>user.name</li>;
})}
</header>
</div>
);
}
export default App;
you are mixing up state.user and state.users
either rename user in configureStore to users or use state.user.userArray

Items doesnt added to Cart (React-Redux)

I'm using React and Redux for creating a shop website. I want to add items to the cart using redux, but cart items it's not getting added only showing an error:
GET http://localhost:3000/api/v1/product/61db003374fe4392e3446ae3 404 (Not Found)
"Uncaught (in promise) Error: Request failed with status code 404"
and I suppose the problem is maybe with ID in action but I'm not sure how to fix it.
Please help me out. Below is my code
// reducer
import { ADD_TO_CART } from '../constants/cartConstants';
export const cartReducer = (state = { cartItems: [] }, action) => {
switch (action.type) {
case ADD_TO_CART:
const item = action.payload;
const isItemExist = state.cartItems.find(
(i) => i.product === item.product
);
if (isItemExist) {
return {
...state,
cartItems: state.cartItems.map((i) =>
i.product === isItemExist.product ? item : i
),
};
} else {
return {
...state,
cartItems: [...state.cartItems, item],
};
}
default:
return state;
}
};
// actions
import axios from 'axios';
import { ADD_TO_CART } from '../constants/cartConstants';
export const addItemToCart = (id, quantity) => async (dispatch, getState) => {
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: ADD_TO_CART,
payload: {
product: data.product._id,
name: data.product.name,
price: data.product.price,
image: data.product.images[0].url,
stock: data.product.stock,
quantity,
},
});
localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems));
};
// store
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import {
productsReducer,
productsDetailsReducer,
} from './reducers/productReducers';
import {
authReducer,
userReducer,
forgotPasswordReducer,
} from './reducers/userReducers';
import { cartReducer } from './reducers/cartReducers';
const reducer = combineReducers({
products: productsReducer,
productDetails: productsDetailsReducer,
auth: authReducer,
user: userReducer,
forgotPassword: forgotPasswordReducer,
cart: cartReducer,
});
let initialState = {
cart: {
cartItems: localStorage.getItem('cartItems')
? JSON.parse(localStorage.getItem('cartItems'))
: [],
},
};
const middleware = [thunk];
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;

redux-toolkit typo error action is not a function

I've looked on other posts and it seemed to be a naming export thing, but I looked over and over my code and can't figure it out. I will appreciate any advice.
this is the error I'm getting:
TypeError: (0 , _redux_wetherSlice__WEBPACK_IMPORTED_MODULE_2__.setLocalLatitude) is not a function
at localWether.js:14
slice component
import { createSlice } from "#reduxjs/toolkit";
export const wetherSlice = createSlice({
name: "wether",
initialState: {
localLocation: {
latitude: "",
longitude: "",
},
reducers: {
setLocalLatitude: (state, action) => {
state.localLocation.latitude = action.payload;
},
setLocalLongitude: (state, action) => {
state.localLocation.longitude = action.payload;
},
},
},
});
export const { setLocalLongitude, setLocalLatitude } = wetherSlice.actions;
export default wetherSlice.reducer;
react component
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setLocalLatitude, setLocalLongitude } from "../../redux/wetherSlice";
const LocalWether = () => {
const dispatch = useDispatch();
const { localLocation } = useSelector((state) => state.wether);
useEffect(() => {
navigator.geolocation.getCurrentPosition((position) => {
try {
console.log(position);
dispatch(setLocalLatitude(position.coords.latitude));
dispatch(setLocalLongitude(position.coords.longitude));
} catch (err) {
console.log(err);
}
});
}, []);
console.log(localLocation);
return <button>Click For Location</button>;
};
export default LocalWether;
store
import { configureStore } from "#reduxjs/toolkit";
import wetherReducer from "../redux/wetherSlice";
const store = configureStore({
reducer: { wether: wetherReducer },
});
export default store;

How to Assign react redux state api get data using axios

i used react 16+ and redux get jsonplaceholder fake data to assign posts state but not working. can't assign the state. how can i assign json values into state using concat method. i check lifecycle methods also but can't get the answer.
Reducer
import * as actiontypes from './actions';
import axios from 'axios';
const initalstate = {
counter: 0,
posts: []
};
const reducer = (state = initalstate, action ) => {
switch (action.type) {
case actiontypes.actionFetchPost:
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(res => {
return {
...state,
posts: state.posts.concat(res.data)
}
});
break;
default :
return state;
}
};
export default reducer;
Redux reducers must be pure functions, it means they should not contain any side effects like calling api.
You need to call api in action creators using redux-thunk package.
Codesandbox
An example action creator:
import {
FETCH_POSTS_STARTED,
FETCH_POSTS_FAILURE,
FETCH_POSTS_SUCCESS
} from "./actionTypes";
import axios from "axios";
export const fetchPosts = () => {
return dispatch => {
dispatch(fetchPostsStarted());
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then(res => {
dispatch(fetchPostsSuccess(res.data));
})
.catch(err => {
dispatch(fetchPostsFailed(err.message));
});
};
};
const fetchPostsStarted = () => {
return {
type: FETCH_POSTS_STARTED,
payload: {
isLoading: true
}
};
};
const fetchPostsSuccess = posts => {
return {
type: FETCH_POSTS_SUCCESS,
payload: {
posts
}
};
};
const fetchPostsFailed = error => {
return {
type: FETCH_POSTS_FAILURE,
payload: {
error
}
};
};
And reducer file:
import {
FETCH_POSTS_STARTED,
FETCH_POSTS_SUCCESS,
FETCH_POSTS_FAILURE
} from "../actions/actionTypes";
const initialState = {
posts: [],
loading: false,
error: null
};
export default function(state = initialState, action) {
switch (action.type) {
case FETCH_POSTS_STARTED:
return {
...state,
loading: true
};
case FETCH_POSTS_SUCCESS:
return {
...state,
loading: false,
error: null,
posts: action.payload.posts
};
case FETCH_POSTS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error
};
default:
return state;
}
}
In store we use redux-thunk like this:
import { createStore, compose, applyMiddleware, combineReducers } from "redux";
import reduxThunk from "redux-thunk";
import postsReducers from "./reducers/postsReducers";
const rootReducer = combineReducers({
posts: postsReducers
});
const store = createStore(rootReducer, compose(applyMiddleware(reduxThunk)));
export default store;
Posts component:
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchPosts } from "./store/actions/postsActions";
class Posts extends Component {
componentDidMount() {
this.props.fetchPosts();
}
render() {
const { posts, loading, error } = this.props;
return (
<div>
{loading && <div>LOADING...</div>}
{error && <div>{error}</div>}
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
}
const mapStateToProps = state => {
const { posts, loading, error } = state.posts;
return {
posts,
loading,
error
};
};
export default connect(
mapStateToProps,
{
fetchPosts
}
)(Posts);
Index.js
import ReactDOM from "react-dom";
import store from "./store/store";
import { Provider } from "react-redux";
import Posts from "./Posts";
function App() {
return (
<div className="App">
<Posts />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
Do api call in action and return promise, use redux-thunk and redux-promise-middleware:
export const myApiCall = (args1, arg2) => async (dispatch, getState) => {
const payload = fetch({ ...config });
return dispatch({ type: 'MY_API_CALL', payload });
}
Then in reducer will have to handle two results:
MY_API_CALL_FULFILLED and MY_API_CALL_REJECTED

Categories

Resources