How can I send data i got from API into an object? - reactjs

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

React Redux thunk - Action is overriding unexpected information

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.

Manage state of global variable react redux

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?

Respond to a Single Redux Action in Multiple Reducers redux

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

react redux api middleware is not working

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.

"Expected the reducer to be a function." only on server

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?

Resources