I'm trying to create a function add product into cart with redux-react
and how can I get my product info from mongoDB into initialState?
this is how my product info looks like:
img_url1: "https://thebeuter.com/wp-content/uploads/2020/06/38-1.jpg"
price: 1290000
title: "BEUTER BACK2BACK ZIPPER WHITE JACKET"
here is my reducer:
import {
ADD_PRODUCT_BASKET,
GET_NUMBERS_BASKET
} from '../actions/type'
const initialState = {
basketNumbers: 0,
cartCost: 0,
products: {
}
}
export default (state = initialState, action) => {
switch (action.type) {
case ADD_PRODUCT_BASKET:
let addQuantity = {
...state.products[action.payload]
}
console.log(addQuantity)
return {
...state,
basketNumbers: state.basketNumbers + 1,
};
case GET_NUMBERS_BASKET:
return {
...state
};
default:
return state;
}
}
Here is my github if you want to look at my code:
https://github.com/nathannewyen/the-beuter
You solve your problem using redux-saga (or redux-thunk) by fetching your data from DB before rendering your page:
productBasket.js (with redux-saga)
import axios from 'axios';
import { action as createAction } from 'typesafe-actions';
import {
put, select, takeLatest,
} from 'redux-saga/effects';
export const FETCH_PRODUCT_BASKET = 'FETCH_PRODUCT_BASKET';
export const FETCH_PRODUCT_BASKET_SUCCESS = 'FETCH_PRODUCT_BASKET_SUCCESS';
export const FETCH_PRODUCT_BASKET_ERROR = 'FETCH_PRODUCT_BASKET_ERROR';
export const actionCreators = {
fetchProductBasket: () =>
createAction(FETCH_PRODUCT_BASKET),
fetchProductBasketSuccess: (products) =>
createAction(FETCH_PRODUCT_BASKET_SUCCESS, { products }),
fetchProductBasketError: (error) =>
createAction(FETCH_PRODUCT_BASKET_ERROR, { error }),
};
export const {
fetchProductBasket,
fetchProductBasketSuccess,
fetchProductBasketError
} = actionCreators;
export const initialState = {
isFetching: false,
isError: false,
basketNumber: 0,
products: []
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_PRODUCT_BASKET:
return {
...state,
isFetching: true,
isError: false
}
case FETCH_PRODUCT_BASKET_SUCCESS:
return {
...state,
isFetching: false,
isError: false,
products: action.payload.products
}
case FETCH_PRODUCT_BASKET_ERROR:
return {
...state,
isFetching: false,
isError: true
}
default:
return state;
}
}
export default reducer;
export function* basketSaga() {
yield takeLatest(FETCH_PRODUCT_BASKET, fetchProductBasketSaga);
}
function* fetchProductBasketSaga() {
try {
// here is code with fetching data
const { data } = yield axios.get('some address');
yield put(fetchProductBasketSuccess(data));
} catch (err) {
console.log(err);
yield put(fetchProductBasketError(err));
}
}
And after that dispatch fetchProductBasket action in useEffect scope in your component. You can show skeleton to user while your data is fetching.
Related
im building a reddit clone, fetching top post. The app should have a favorites post CRUD.
So what i build is a two columns layout, left side is the post list and right part has post detail OR favorites list when switch is ON.
All this is handled by two reducers: favorites and post. The issue is: when i fire set favorites action, this is overriding post data for some reason. I just reviewed the whole flow several times and i cant fine what is going on.
This is the redux dev tools state, with post fetched and then with show favorites action
This is favorites reducer:
import {
FETCH_FAVORITES_REQUEST,
FETCH_FAVORITES_SUCCESS,
FETCH_FAVORITES_ERROR,
SHOW_FAVORITES
} from '../constants';
const initialState = {
data: [],
isLoading: false,
error: false,
show: false
};
const favorites = (state = initialState, action) => {
switch (action.type) {
case FETCH_FAVORITES_REQUEST:
return {
...state,
isLoading: true
};
case FETCH_FAVORITES_SUCCESS: {
return {
...state,
isLoading: false,
data: action.payload
};
}
case FETCH_FAVORITES_ERROR:
return { ...state, error: true, isLoading: false };
case SHOW_FAVORITES:
return { ...state, show: !state.show };
default:
return initialState;
}
};
export default favorites;
and this is posts reducer:
import {
FETCH_POST_REQUEST,
FETCH_POST_SUCCESS,
FETCH_POST_ERROR,
SET_READED,
DISMISS_ALL,
DISMISS_POST
} from '../constants';
const initialState = {
data: [],
isLoading: false,
error: false,
lastFetched: null,
allDismissed: false
};
const posts = (state = initialState, action) => {
switch (action.type) {
case FETCH_POST_REQUEST:
return {
...state,
isLoading: true
};
case FETCH_POST_SUCCESS: {
const data = [...state.data, ...action.payload];
return {
...state,
data,
lastFetched: action.lastFetched,
isLoading: false,
allDismissed: false
};
}
case FETCH_POST_ERROR:
return { ...state, error: true, isLoading: false };
case SET_READED: {
const newData = state.data;
const foundIndex = newData.findIndex((x) => x.id === action.payload);
newData[foundIndex].readed = true;
return {
...state,
data: newData
};
}
case DISMISS_ALL: {
return {
...state,
allDismissed: true,
data: []
};
}
case DISMISS_POST: {
return {
...state,
data: state.data.filter((post) => post.id !== action.payload)
};
}
default:
return initialState;
}
};
export default posts;
This is the component from where show favorites action is being dispatched:
import React from 'react';
import styled, { css } from 'styled-components';
import Toggle from 'react-toggle';
import { useDispatch, useSelector } from 'react-redux';
import { useMediaQuery } from 'react-responsive';
import { DEVICE_SIZE } from '../constants';
import { showFavorites } from '../actions/favorites';
const ToogleFavorites = styled.div`
position: fixed;
bottom: 5%;
right: 5%;
text-align: end;
z-index: 2;
${({ isMobile }) =>
isMobile &&
css`
font-size: small;
`}
`;
export default () => {
const dispatch = useDispatch();
const { show } = useSelector((state) => state.favorites);
const isTabletOrBigger = useMediaQuery({ minDeviceWidth: DEVICE_SIZE.tablet });
const handleToogle = () => dispatch(showFavorites());
return (
<ToogleFavorites isMobile={isTabletOrBigger}>
<Toggle defaultChecked={show} onChange={handleToogle} />
<div>Toogle favorites</div>
</ToogleFavorites>
);
};
favorites action (seems not big deal):
export const showFavorites = () => ({
type: SHOW_FAVORITES
});
Let me know anything extra info. Thanks a lot!
your reducer has the default case to return intialState which means any action that isn't explicitly handled resets the state. you want to return state instead.
How do I get the state of this? I only need to put it as false and true the time I want at my components, but i`m doing something wrong, i know how do it when calling an API, but not like this.
I have this actions:
import { HIDE_MENU, ESTADO_MENU } from "./types";
export const hideMenu = dispatch => {
return dispatch({
type: HIDE_MENU
});
};
export const estadoDoMenu = open => dispatch => {
dispatch({
type: ESTADO_MENU
});
};
and this reducer:
import { HIDE_MENU, ESTADO_MENU } from "../actions/types";
const initialState = {
open: true
};
export default function(state = initialState, action) {
switch (action.type) {
case HIDE_MENU:
return {
...state,
open: false
};
case ESTADO_MENU:
console.log("chega aqui");
return {
...state
};
default:
return state;
}
}
but calling it like this:
componentDidMount() {
console.log("Estado do Menu: ", this.props.estadoDoMenu());
}
I get undefined at the console, what is wrong?
I am using multiple reducers in my project and then combining them with combineReducers() function and have all actions in single file. when i dispatch the action, it is returning me state values to undefined. I think It can't find out because of multiple reducerse. But when i use single reducer file. It is working fine. Can anyone please tell me what the issue.It is how i am combining the reducers.
const rootReducer = combineReducers({
isMobileReducer,
imageSliderReducer
})
and now passing to store, like below:
let store = createStore(rootReducer,applyMiddleware(thunk))
and in frontend how i am accessing state
const mapStateToProps = (state) => ({
images: state.images,
isMobile: state && state.isMobile
})
imageSliderReducer.js
import {
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from '../actions/actionTypes'
const initialState = {
images:[],
error:null
}
const imageSliderReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_IMAGES_BEGIN:
return {...state,error:null}
case FETCH_IMAGES_SUCCESS:
return {...state,images:action.payload.images}
case FETCH_IMAGES_FAILURE:
return {...state,error:action.payload.error,images:[]}
default:
return state
}
}
export default imageSliderReducer;
isMobileReducer.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
} from '../actions/actionTypes'
const initialState = {
isMenuOpen: null,
isMobile: false
}
const isMobileReducer = (state = initialState, action) => {
switch (action.type) {
case OPEN_MENU:
return {...state, isMenuOpen: true}
case CLOSE_MENU:
return {...state, isMenuOpen: false}
case SET_DEVICE_TYPE:
return {...state, isMobile: action.isMobile}
default:
return state
}
}
export default isMobileReducer;
actionCreator.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from './actionTypes'
export function openMenu(isMobile) {
return {
type: OPEN_MENU
}
}
export function closeMenu(isMobile) {
return {
type: CLOSE_MENU
}
}
export function setDeviceType (isMobile) {
return {
type: SET_DEVICE_TYPE,
isMobile: isMobile
}
}
export function fetchImages() {
return dispatch => {
dispatch(fetchImagesBegin());
return fetch("https://7344.rio.com/wp-json/customapi/homeslider")
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchImagesSuccess(json.posts));
return json.posts;
})
.catch(error => dispatch(fetchImagesFailure(error)));
};
}
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
export const fetchImagesBegin = () => ({
type: FETCH_IMAGES_BEGIN
});
export const fetchImagesSuccess = images => ({
type: FETCH_IMAGES_SUCCESS,
payload: { images }
});
export const fetchImagesFailure = error => ({
type: FETCH_IMAGES_FAILURE,
payload: { error }
});
Try using this:
const mapStateToProps = (state) => ({
images: state.imageSliderReducer.images,
isMobile: state.isMobileReducer.isMobile
})
I am using Redux API Middleware to call the api for the data
Action.js
import { CALL_API } from 'redux-api-middleware';
export const FETCH_POSTS = 'FETCH_POSTS';
export const FETCH_POSTS_SUCCESS = 'FETCH_POSTS_SUCCESS';
export const FETCH_POSTS_FAILURE = 'FETCH_POSTS_FAILURE';
export const fetchPosts = () => ({
[CALL_API]: {
types: [
{
type: FETCH_POSTS,
payload: (action, state) => ({ action: state })
},
{
type: FETCH_POSTS_SUCCESS,
payload: (action, state, response) => {
return response
}
},
FETCH_POSTS_FAILURE
],
endpoint: 'http://localhost:8080/v1/career/',
method: 'GET',
}
});
Reducer.js
import {
FETCH_POSTS,
FETCH_POSTS_SUCCESS,
FETCH_POSTS_FAILURE
} from '../actions/Action';
import {combineReducers} from 'redux'
const INITIAL_STATE = { postsList: { posts: [], error: null, loading: false } };
export const posts=(state = INITIAL_STATE, action)=> {
let error;
switch(action.type) {
case FETCH_POSTS:
return { ...state, postsList: { posts: [], error: null, loading: true} };
case FETCH_POSTS_SUCCESS:
return { ...state, postsList: { posts: action.payload, error: null, loading: false } };
case FETCH_POSTS_FAILURE:
error = action.payload.data || { message: action.payload.message };
return { ...state, postsList: { posts: [], error: error, loading: false } };
default:
return state;
}
export const reducers=combineReducers({
posts:posts
});
export default reducers;
Store.js
import {
applyMiddleware,
createStore,compose
} from 'redux';
import { apiMiddleware } from 'redux-api-middleware';
import reducers from './reducer'
export function ConfigureStore(IntitialState={}){
const stores=createStore(reducers,IntitialState,compose(
applyMiddleware(apiMiddleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
return stores;
};
export const store=ConfigureStore()
I can see only the FETCH POSTS is running and when i check the state i get this
I checked the network section of the developer tools.The response is coming from the server
and my response is
I dont know why this not working.Please some one help me .Thanks.
I am building an isomorphic app and I have a strange problem with my store and reducers. When I import my reducers in the client side store, it all works:
import reducers from '../Reducers';
...
let store = createStore(reducers, initial, composeEnhancers(applyMiddleware(...middleware)));
export default store;
But when I try to do the same on the server:
import reducers from '../source/js/Reducers';
I am getting error in the console
Error: Expected the reducer to be a function.
My reducers are like this:
import { INSERT_POST, INSERT_CONTENT, BUMP_PAGE, FETCH_COLLECTION } from '../Actions/Content';
const defaultState = {
currentPage: 0,
nextPage: 1,
content: [],
fetched: []
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case INSERT_POST:
return { ...state, content: [ ...state.content, action.payload ], fetched: [ ...state.fetched, action.url ] };
case INSERT_CONTENT:
const newState = {...state};
newState.content[action.payload.id].content = action.payload.data;
return newState;
case `${FETCH_COLLECTION}_SUCCESS`:
return { ...state, fetched: [ ...state.fetched, action.meta.previousAction.payload.request.url ]};
case BUMP_PAGE:
return { ...state, currentPage: state.nextPage, nextPage: ++state.nextPage };
default:
return state;
}
};
export default reducer;
...
import { START_TRANSITION, END_TRANSITION, TOGGLE_TRANSITION } from '../Actions/Transitions';
const defaultState = {
loaded: true
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case START_TRANSITION:
return { ...state, loaded: false };
case END_TRANSITION:
return { ...state, loaded: true };
case TOGGLE_TRANSITION:
return { ...state, loaded: !state.loaded };
default:
return state;
}
};
export default reducer;
And the main reducer:
import { combineReducers } from 'redux';
import Transitions from './Transitions'
import Content from './Content';
export default combineReducers({
Transitions,
Content
});
I have no idea of what to do with this. It's the first time I ever see such error. What can I do?