Saga Setup, fetch is not executed - redux

I have the following setup for my saga:
In saga.js
import { put, call } from "redux-saga/effects";
import { takeLatest } from "redux-saga";
import { SET_BASE_CURRENCY, SET_CURRENCY_REPONSE } from "./duck";
function* fetchCurrencyExchangeRate() {
const response = yield call(
fetch,
"https://api.exchangeratesapi.io/latest?base=USD"
);
const data = yield call([response, "json"]);
// const json = yield fetch(
// "https://api.exchangeratesapi.io/latest?base=USD"
// ).then(response => response.json());
yield put({ type: SET_CURRENCY_REPONSE, json: data });
}
export default function* rootSaga() {
yield takeLatest([SET_BASE_CURRENCY], fetchCurrencyExchangeRate);
}
In duck.js
import { defineAction } from "redux-define";
import { createAction, handleActions } from "redux-actions";
export const initialState = {
exchangeRate: 3.06,
baseCurrency: "SGD",
exchangeCurrency: "MYR",
amountToConvert: 0.0,
currencyResponse: ""
};
//Action-types
export const SET_EXCHANGE_RATE = defineAction("SET_EXCHANGE_RATE");
export const SET_BASE_CURRENCY = defineAction("SET_BASE_CURRENCY");
export const SET_EXCHANGE_CURRENCY = defineAction("SET_EXCHANGE_CURRENCY");
export const SET_AMOUNT_TO_CONVERT = defineAction("SET_AMOUNT_TO_CONVERT");
export const SET_CURRENCY_REPONSE = defineAction("SET_CURRENCY_REPONSE");
//Action-creators
export const setExchangeRate = createAction(
SET_EXCHANGE_RATE,
params => params
);
export const setExchangeCurrency = createAction(
SET_EXCHANGE_CURRENCY,
params => params
);
export const setBaseCurrency = createAction(
SET_BASE_CURRENCY,
params => params
);
export const setAmountToConvert = createAction(
SET_BASE_CURRENCY,
params => params
);
export const setCurrencyResponse = createAction(
SET_CURRENCY_REPONSE,
params => params
);
//reducer
const reducer = handleActions(
{
[setExchangeRate]: (state, { payload }) => ({
...state,
exchangeRate: payload
}),
[setExchangeCurrency]: (state, { payload }) => ({
...state,
exchangeCurrency: payload
}),
[setBaseCurrency]: (state, { payload }) => ({
...state,
baseCurrency: payload
}),
[setAmountToConvert]: (state, { payload }) => ({
...state,
amountToConvert: payload
}),
[setCurrencyResponse]: (state, { payload }) => ({
...state,
currencyResponse: payload
})
},
initialState
);
export default reducer;
//Selector
export const selectExhangeRate = state => state.reducer.exchangeRate;
export const selectExchangeCurrency = state => state.reducer.exchangeCurrency;
export const selectBaseCurrency = state => state.reducer.baseCurrency;
export const selectAmountToConvert = state => state.reducer.amountToConvert;
In index.js where the saga is setup
import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware, compose } from "redux";
import ReduxThunk from "redux-thunk";
import reducers from "./configureStore/reducers";
import { Provider } from "react-redux";
import App from "./App";
import rootSaga from "./configureStore/saga";
import createSagaMiddleware from "redux-saga";
const sagaMiddleware = createSagaMiddleware();
const middlewares = [ReduxThunk];
const store = createStore(
reducers,
compose(
applyMiddleware(...middlewares),
applyMiddleware(sagaMiddleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
sagaMiddleware.run(rootSaga);
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
However, for some reason, I can't get the call function or the fetch function to work. I wanted it to trigger the api call when SET_BASE_CURRENCY action is triggered. Is there a problem with my setup or is it the way I am calling saga is wrong? Full code is inside this sandbox : https://codesandbox.io/s/todoapp-with-redux-and-normalized-store-jkp8z

Related

TypeError: (0 , _react.createContext) is not a function on Nextjs using Redux

im new in using redux and tried to use it with the help of online tutorials. nut im seeing this error:
Server Error TypeError: (0 , _react.createContext) is not a function
This error happened while generating the page. Any console logs will be displayed in the terminal window.
im providing my codes bellow:
authSlice.js file:
import { createSlice } from "#reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";
const initialState = {
authState: false,
userInfo: {},
authToken: ""
}
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setAuthState(state, action) {
state.authState = action.payload
}
, setUserInfo(state, action) {
state.userInfo = action.payload
},
setToken(state, action) {
state.authToken = action.payload
},
setAuth(state, action) {
state.authState = action.payload.authState;
state.userInfo = action.payload.userInfo;
state.authToken = action.payload.authToken;
}
},
extraReducers: {
[HYDRATE]: (state, action) => {
return {
...state,
...action.payload.auth
}
}
}
})
export const { setAuthState, setUserInfo, setToken, setAuth } = authSlice.actions
export const selectAuthState = (state) => state.auth.authState;
export const selectAuthToken = (state) => state.auth.authToken;
export const selectUserInfo = (state) => state.auth.userInfo;
export default authSlice.reducer
store.js codes:
import { configureStore, ThunkAction, Action } from "#reduxjs/toolkit";
import { authSlice } from "./authSlice";
import { createWrapper } from "next-redux-wrapper";
const makeStore = () =>
configureStore({
reducer: {
[authSlice.name]: authSlice.reducer,
},
devTools: true,
});
const store = makeStore()
export default store
components where i tried to use redux:
import { useRouter } from "next/navigation";
import { useDispatch, useSelector } from "react-redux";
import {
selectAuthState,
selectAuthToken,
selectUserInfo,
setAuthState,
setUserInfo,
} from "#/data/authSlice";
function Sidebar() {
const router = useRouter();
const dispatch = useDispatch();
const authState = useSelector(selectAuthState);
const authToken = useSelector(selectAuthToken)
const userInfo = useState(selectUserInfo)
useEffect(() => {
if (!authState) {
router.push("/")
}
}, [router.asPath]);
// rest of the codes
import axios from "axiosConfig";
import { useDispatch, useSelector } from "react-redux";
import {
selectAuthState,
selectAuthToken,
setAuthState,
setUserInfo,
} from "#/data/authSlice";
// toastify
// import { toast } from 'react-toastify';
// import 'react-toastify/dist/ReactToastify.css';
// const notify = (text) => {
// toast.success(text , {position: toast.POSITION.BOTTOM_RIGHT})
// }
const LoginPage = () => {
const router = useRouter();
const dispatch = useDispatch();
const authState = useSelector(selectAuthState);
useEffect(() => {
const token = authState;
if (token) {
router.push("/Dashboard");
} else {
}
}, [router.asPath]);
// rest of the codes
i tried to reinstall redux and react-redux but didnt helped.
also tried Remove the node_modules
Remove package-lock.json
npm install again.
but nothing happend.

My createAsyncThunk doesn't work with my api function

I have this in postsSlice
export const getPosts = createAsyncThunk(
'posts/getPosts',
async (thunkAPI)=> {
const response = await api.fetchPosts()
// const response = await fetch('http://localhost:3002/api/posts').then(
// (data) => data.json()
// )
return response.data
})
and commented response works fine but const response = await api.fetchPosts() doesn't work properly, it sends me errors that posts.map is not a function but data Arrays looks fine
api.fetchPosts() looks like this
import axios from "axios"
const API = axios.create({ baseURL: "http://localhost:3002/api"})
API.interceptors.request.use((req) => {
if (localStorage.getItem('access_token')) {
req.headers.Authorization = `Bearer ${
JSON.parse(localStorage.getItem('access_token')).token
}`
}
return req
})
export const fetchPosts = () => API.get(`/posts`)
here is where map function is
import React, {useEffect, useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import CardMain from "../../components/CardMain/CardMain";
import {createPost, getPosts} from "../../redux/features/posts/postsSlice"
const Main = () => {
const dispatch = useDispatch()
const {posts} = useSelector((state) => state.posts)
useEffect(() => {
dispatch(getPosts())
}, []);
console.log(posts)
return (
<div>
<div>
{
posts.map(user=>(
<CardMain post={user} key={user._id}/>
))
}
</div>
</div>
);
};
export default Main;
In your console.log you can see, that posts is actually an object in the form { data: [ .... ] } - you cannot .map on an object.
So either you need to return response.data.data in your thunk, or do posts.data.map(... instead of posts.map(... (or change your api method to directly return correct unnested data)

Navigator doesn't Re-render after redux state change in React Navigation 5

I'm using a stack navigator from react navigation v5 with redux. The stack navigator should render AuthScreen when isAuthenticated is false and render HomeScreen when isAuthenticated changes to true.
AppNav.js
import React, {useState, useEffect} from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import { connect } from 'react-redux';
import AuthScreen from '../screens/AuthScreen';
import HomeScreen from '../screens/HomeScreen';
const Stack = createStackNavigator();
const AppNav = ({isAuthenticated}) => {
const [logged, setLogged] = useState(false)
useEffect(() => {
if(isAuthenticated) {
console.log(logged);
setLogged(true);
} else {
setLogged(false);
console.log(logged);
}
},[isAuthenticated])
return (
<NavigationContainer>
<Stack.Navigator>
{
!logged?
<Stack.Screen name='Auth' component={AuthScreen} options={{headerShown: false}} />
:<Stack.Screen name='Home' component={HomeScreen} options={{headerShown: false}} />
}
</Stack.Navigator>
</NavigationContainer>
);
}
const mapStateToProps = ({isAuthenticated}) => {
return {
isAuthenticated
};
}
export default connect(mapStateToProps, null)(AppNav)
userAction.js
import {LOGIN_WITH_FACEBOOK} from './types';
export const loginWithFacebook = () => async(dispatch) => {
dispatch( { type: LOGIN_WITH_FACEBOOK, payload: {isAuthenticated: true} } );
}
userReducer.js
import {LOGIN_WITH_FACEBOOK} from '../actions/types.js';
const INITIAL_STATE = {
isAuthenticated: false
};
const userReducer = (state=INITIAL_STATE, action) => {
switch(action.type){
case LOGIN_WITH_FACEBOOK:
return {...state, ...action.payload};
default:
return state;
}
}
export default userReducer
rootReducer.js
import {combineReducers} from 'redux';
import userReducer from './userReducer';
const rootReducer = combineReducers({
user: userReducer
})
export default rootReducer
Fixed it by accessing the key of userReducer which is state.user.
AppNav.js
const mapStateToProps = (state) => {
return {
isAuthenticated: state.user.isAuthenticated
};
}
export default connect(mapStateToProps, null)(AppNav)

Why are my props `undefined` when using redux and react Native?

I followed all the steps to create a store, but I when I try to access my props, they are undefined. I am using react Native , redux, and the connect component from 'react-redux'. Please help . I cant move forward.
this is where I connect props to state :
const mapStateToProps = (state) => ({
location : state.location
})
export default connect(mapStateToProps)(MapsScreen);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent:'center',
alignContent:'center',
}
})
This is the component :
import LocationComp from './location'
import {connect} from 'react-redux';
import * as actions from '../../../redux/actions'
import MapView from 'react-native-maps';
export class MapsScreen extends React.Component {
state = {
isLoading : true
}
handleLanguage = (loco) => {
store.dispatch(actions.newLocation(loco))
this.setState({ isLoading: !this.state.isLoading })
console.log(store.getState())
}
render() {
return (
<View style = {{flex :1}}>
{this.state.isLoading === true ?
(
<LocationComp getLocation = {this.handleLanguage}/>
):(
<MapView
style={{flex:1}}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}>
{console.log(this.props.location)}
</MapView>
)}
</View>
);
}
}
My store:
import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import {addTest} from './actions'
import thunk from 'redux-thunk'
export default store = createStore(reducer, applyMiddleware(thunk))
My reducer :
import {UPDATE_TEST, UPDATE_LOCATION,} from './actions'
import { combineReducers} from 'redux'
const merge = (prev, next ) => Object.assign({}, prev, next)
const hustleReducer = (state = [], action) => {
if(action.type === UPDATE_TEST) {
return [...state, action.payload]
}
return state
}
const locoReducer = (state = {}, action) => {
if(action.type === UPDATE_LOCATION){
return merge(state.location, action.payload)
}
return state
}
export default reducer = combineReducers({
hustleList : hustleReducer,
location : locoReducer,
})
my actions :
/// action creators
export const UPDATE_TEST= 'UPDATE_TEST'
export const UPDATE_LOCATION = 'UPDATE_LOCATION'
export const addTest = newContact => ({
type : UPDATE_TEST,
payload : newContact
})
export const newLocation = newLocation =>({
type : UPDATE_LOCATION,
payload : newLocation
})
You dont need merge, try return something like return {{...state.location}, {...action.payload}}

Action.type undefined redux

No matter what I do, I can't get rid of the mistake. I have often rewritten the actions but the error remains. I also wrote thunk at the top of the createstore. It would be great if you could support me a little bit.
My action, nothing special here only a fetch call to get my players
import fetch from "cross-fetch"
export const SET_PLAYERS = "setplayers"
export const setPlayers = players => {
return{
type: "setplayers",
players
}
}
export const fetchPlayers = () => (dispatch, getState) => {
return fetch("http://localhost:4444/api/players")
.then(response => response.json())
.then(players => {
dispatch(setPlayers(players))
}).catch(err => {
console.log("Could not fetch assortments" , err)
})
}
Component, at this point in time only a dummy to invoke the action:
import React from "react"
import PropTypes from "prop-types"
import { fetchPlayers } from "./action"
import { connect } from "react-redux"
import EnhancedTable from "../components/list/List"
import getPlayers from "./reducer"
class PlayerTable extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
componentDidMount(){
this.props.fetchPlayers()
}
render() {
console.log("#######", this.props.players)
return (
<EnhancedTable />
)
}
}
PlayerTable.propTypes = {
classes: PropTypes.object.isRequired,
}
const mapStateToProps = state => ({
players: getPlayers(state)
})
export default connect(mapStateToProps, { fetchPlayers })(PlayerTable)
Reducer
import { SET_PLAYERS } from "./action"
const setPlayers = (state={}, action) => {
console.log("ACTION", action)
switch (action.type) {
case SET_PLAYERS:
return {...state, players: action.players}
default:
return state
}
}
export default setPlayers
export const getPlayers = state => ([])
CombinedReducers
import { combineReducers } from "redux"
import { reducer as formReducer } from "redux-form"
import showProgressbar from "../components/progressbar/reducer"
import showSnackBar from "../components/snackbar/reducer"
import setPlayers from "../player/reducer"
export default combineReducers({
form: formReducer,
showProgressbar,
showSnackBar,
setPlayers
})
CreateStore
import App from "./App"
import React from "react"
import rootReducer from "./reducers"
import thunk from "redux-thunk"
import { render } from "react-dom"
import { createStore, applyMiddleware, compose } from "redux"
import { Provider } from "react-redux"
import { createLogger } from "redux-logger"
const store = createStore(
rootReducer,
compose(applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
))
render(
<Provider store={store}>
<App />
</Provider>,
/* eslint-disable*/
document.getElementById("root")
/* eslint-enable */
)
You've defined mapStateToProps properly, but don't you need to do the same with mapDispatchToProps for the second argument to connect()?
const mapStateToProps = state => ({
players: getPlayers(state)
})
const mapDispatchToProps = dispatch => ({
fetchPlayers() {
dispatch(fetchPlayers())
}
})
export default connect(mapStateToProps, mapDispatchToProps)(PlayerTable)

Resources