Redux data undefined - javascript

In logger seen anything is normal data loaded successfully.
You can see it by follow this link https://i.stack.imgur.com/uTLpr.jpg
But why this crypto props is undefined and how to fix it.
Does anyone have any idea?
Component
class CryptoContainer extends Component {
componentWillMount(){
this.props.Fetchcoin()
}
renderCoinCards() {
const { crypto } = this.props;
console.log('Crypto : '+crypto)
return crypto.data.map((coin,index) => //Add this
<CoinCard
key={coin.name}
coin_name={coin.name}
symbol={coin.symbol}
price_usd={coin.price_usd}
percent_change_24h={coin.percent_change_24h}
percent_change_7d={coin.percent_change_7d}
/>
)
}
}
function mapStatetoProps(state){
return{
crypto:state.crypto
}
}
export default connect(mapStatetoProps,{Fetchcoin})(CryptoContainer)
>
Action
export default function FetchCoin(){
return dispatch => {
dispatch({type:FETCHING_COIN_DATA})
return axios.get(`https://api.coinmarketcap.com//v1/ticker/?limit=10`)
.then(res => {
dispatch({type:FETCHING_COIN_DATA_SUCCESS,payload:res.data})
})
.catch(err => {
dispatch({type:FETCHING_COIN_DATA_FAIL,payload:err.data})
})
}
}
Reducer
const initialState = {
isFetching: null,
data: [],
hasError: false,
errorMessage: null
}
export default function (state = initialState, action) {
switch (action.type) {
case FETCHING_COIN_DATA:
return Object.assign({}, state, {
isFetching: true,
data: null,
hasError: false,
errorMessage: null
})
case FETCHING_COIN_DATA_SUCCESS:
return Object.assign({}, state, {
isFetching: false,
data: action.payload,
hasError: false,
errorMessage: null
})
case FETCHING_COIN_DATA_FAIL:
return Object.assign({}, state, {
isFetching: false,
data: action.payload,
hasError: true,
errorMessage: action.err
})
default:
return state
}
}
And store
const middleware = applyMiddleware(thunk,promise,logger)
const rootReducer = combineReducers({
crypto:CyptoReducer
})
const Store = createStore(
rootReducer,middleware
)
export default Store
I fixed misspelling in store but when I add crypto.data.map() in renderCoinCard
data seem still not working debugger shown
TypeError: Cannot read property 'map' of null

I think there is a problem with your declaration of rootReducer.Here you have mentioned "cypto" instead of "crypto". Fix this and it will work as here only redux declares a reducer and as you have declared here as "cypto" it expects "cypto" and fails.

Related

why the profile inside the state return null instead of empty object after update?

I have a problem with my redux reducer.It doesn't return the expected state after dispatching the getCurrentProfile action, it returns the initial state which is "null" instead of "{}", which is fetched with an ajax request, so when the network return the result the state profile change to the result returned but when it is an error returned it stay null instead of empty object, so that is my code:
enter image description here
profileAcction.js :
import axios from 'axios';
import { GET_PROFILE, PROFILE_LOADING, CLEAR_CURRENT_PROFILE} from './types';
//Loading profile
const setProfileLoading = () => {
return {
type: PROFILE_LOADING
}
};
// Clear current profile
export const clearCurrentProfile = () => {
return {
type: CLEAR_CURRENT_PROFILE,
}
}
// Get current profile
export const getCurrentProfile = () => dispatch => {
dispatch(setProfileLoading());
axios.get('/api/profile')
.then(res => dispatch({
type: GET_PROFILE,
payload: res.data
})).catch(error =>
dispatch({
type: GET_PROFILE,
payload: {}
}))
};
profileReducer.js:
import {GET_PROFILE, PROFILE_LOADING, CLEAR_CURRENT_PROFILE} from '../actions/types';
const initialState = {
profile: null,
profiles: null,
loading: false
};
const profileReducer = (state=initialState, action) => {
switch(action.type) {
case PROFILE_LOADING:
return {
...state,
loading: true
}
case GET_PROFILE:
return {
...state,
profile: action.payload,
loading: false
}
case CLEAR_CURRENT_PROFILE:
return {
...state,
profile: null,
loading: false
}
default:
return state;
}
};
export default profileReducer;

Pervious state is removed when I update state in react native redux

I call get_user_profile_api inside the app after login. On successful login my appĀ has user and token in the state. But as soon as GET_USER_PROFILE_SUCCESS is called, the state is left only with userData and isLoading. user and token are removed from the state.
import { CONST } from '../../utils/Const';
import * as types from './types';
const initialState = {
isLoading: false,
user: null,
userData: null,
isLoggedIn: false,
token: '',
};
export default authReducer = (state = initialState, action) => {
console.log('action :: ', action);
switch (action.type) {
case types.GET_USER_PROFILE_LOADING:
case types.LOGIN_LOADING:
return {
isLoading: true,
};
case types.GET_USER_PROFILE_SUCCESS:
return {
...state,
isLoading: false,
userData: action.payload,
};
case types.LOGIN_SUCCESS:
return {
...state,
isLoading: false,
isLoggedIn: true,
user: action.payload.user,
token: action.payload.token,
};
case types.LOGIN_ERROR:
case types.GET_USER_PROFILE_ERROR:
return {
...state,
isLoading: false,
};
default:
return {
...state,
isLoading: false,
};
}
};
there is nothing wrong with this code I think the issue is where you are calling these actions from and you can call them inside a use-effect hook to get a user profile if there is a token or maybe you are not mapping state to props correctly
I was not writing ...state in the LOADING case. That's why my state was being removed.

I am getting mutation of state error between dispatches from redux

i am getting the following error:
A state mutation was detected between dispatches, in the path 'notifications.adhans.AsrAdhan'. This may cause incorrect behavior. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)]
Following is my notifications reducer in notifications.ts file.
import {
RESTORE_NOTIFICATIONS,
SET_ADHAN,
SET_ADHANTOGGLE,
SET_REMINDER,
SET_REMINDERTOGGLE,
} from "./../constants";
export const initialState = {
reminderToggle: true,
adhanToggle: true,
adhans: {
FajrAdhan: false,
DhuhrAdhan: true,
AsrAdhan: false, //--->getting mutation error for this
MaghribAdhan: true,
IshaAdhan: true,
},
reminders: {
FajrReminder: false,
DhuhrReminder: false,
AsrReminder: true,
MaghribReminder: false,
IshaReminder: true,
SunriseReminder: true,
MidnightReminder: false,
},
};
export default (state = initialState, action: AnyAction): notificationsT => {
switch (action.type) {
case SET_REMINDERTOGGLE:
return {
...state,
reminderToggle: action.payload,
};
case SET_ADHANTOGGLE:
return {
...state,
adhanToggle: action.payload,
};
case SET_ADHAN:
return {
...state,
adhans: {
...state.adhans,
[action.payload.key]: action.payload.value,
},
};
case SET_REMINDER:
return {
...state,
reminders: {
...state.reminders,
[action.payload.key]: action.payload.value,
},
};
case RESTORE_NOTIFICATIONS:
return { ...action.payload };
default:
return state;
}
};
error stack points at src\screens\Home.tsx:127:14 in RestoreState.
Following is the relevant code for Home.tsx
import AsyncStorage from "#react-native-async-storage/async-storage";
import * as actionTypes from "../store/constants";
import { initialState as notifInitState } from "../store/reducers/notifications";
...
const updatedNotificationsstate = { ...notifInitState };
const adhanKeys = Object.keys(notifInitState.adhans);
const keysArray = [
...adhanKeys,
...//other state keys
];
const Home = ({ navigation }) => {
const dispatch = useAppDispatch();
//When component mounts on start, Restore the redux state
React.useEffect(() => {
const RestoreState = async () => {
const savedState = await AsyncStorage.multiGet(keysArray);
savedState.forEach(([key, value]) => {
...
if(value){
//notifications
if (adhanKeys.includes(key))
return (updatedNotificationsstate.adhans[key] = JSON.parse(value));
...
}
});
dispatch({
type: actionTypes.RESTORE_NOTIFICATIONS,
payload: updatedNotificationsstate,
});
};
RestoreState();
}, []);
---
return (
<Layout>
..
</Layout>
);
};
export default Home;
what am i doing wrong here???
Please note I have removed typesrcipt types for javascript coders convenience.
updatedNotificationsstate.adhans[key] = JSON.parse(value) looks to be a mutation.
You've correctly created a shallow copy of updatedNotificationsstate but all the elements are still references to the originals in state, i.e. updatedNotificationsstate.adhans is a reference to the previous state. You must also shallow copy any nested state properties that are being updated.
if (adhanKeys.includes(key)) {
return (updatedNotificationsstate.adhans = { // <-- new object reference
...updatedNotificationsstate.adhans, // <-- shallow copy previous
[key]: JSON.parse(value) // <-- update property
});
}

Redux: altering different parts of the initial state in Reducer according to Actions

I have the following Reducer:
const initialState = {}
const dishReducer = (state = initialState, action) => {
switch (action.type) {
case 'LOAD_DISHES':
return (action.dishes)
case 'LOAD_DISHES_ERROR':
console.log("load dishes error")
return state
case 'LOAD_DISHES_SUCCESS':
console.log("load dishes success")
return state
default:
return state;
}
};
export default dishReducer;
And the following action(s):
import {database} from '../../config/fbConfig'
export const startLoadingDishes = (dishes) => {
return (dispatch) =>{
return database.ref('products-dishes').once('value').then((snapshot) => {
let dishes = {}
snapshot.forEach((childSnapshot) => {
let parentkey = childSnapshot.key
let dishArray = [];
childSnapshot.forEach((dish) =>{
dishArray.push(dish.val())
});
dishes[childSnapshot.key] = dishArray;
})
dispatch(loadDishes(dishes))
}).then(() => {
dispatch({ type: 'LOAD_DISHES_SUCCESS' });
}).catch(err => {
dispatch({ type: 'LOAD_DISHES_ERROR' }, err);
});
}
}
export const loadDishes = (dishes) => {
return {
type: 'LOAD_DISHES',
dishes
}
}
The 'startLoadingDishes' action is called inside the componentDidLoad() of a certain Component. However, I want to alter the initial state of my dishReducer so that it includes additional information, as follows:
const initialState = {
value : {},
loaded: false,
loading: false,
error: false
}
So now 'action.dishes' returned by reducer [in 'LOAD_DISHES' case] should be put inside the 'value' part of the state, instead of it being the whole state. Also, the 'loaded' part of the state should be set to true if dishes have already been loaded earlier, and so on. I understand this is fairly simple but as I am new to React+Redux, I don't know how to alter the Action/Reducer codes properly (while keeping state immutability). Any help is appreciated.
I originally asked the question, here is how I solved it (not sure if this is the 'best' way though):
New reducer file:
const initialState = {
value : {},
loaded: false,
loading: false,
error: false
}
const dishReducer = (state = initialState, action) => {
switch (action.type) {
case 'LOAD_DISHES':
return {
value: action.dishes,
loading: !state.loading,
loaded: false, //this might need to be set to true
error: false
}
case 'LOAD_DISHES_ERROR':
console.log("load dishes error")
return {
...state, //or: state.value, as the other parts of state are being overwritten below
loaded: false,
loading: false,
error: true
}
case 'LOAD_DISHES_SUCCESS':
console.log("load dishes success")
return {
...state, //better: state.value
loaded: true,
loading: false,
error: false
}
default:
return state;
}
};
export default dishReducer;
No change in actions file.
Now, inside the 'Main' component, I was originally accessing the state as such:
class Main extends Component {
componentDidMount() {
this.props.startLoadingDishes();
}
render() {
return (
//some code
)
}
}
const mapStateToProps = (state) => {
return {
dishes: state.dishes //to access dishes: dishes.value
}
}
export default connect(mapStateToProps, actions)(Main)
The Main component code also stayed the same, with the difference that now I use 'dishes.value' instead of just 'dishes' to access the value of dishes from the state (and dishes.loaded for loaded, and so on). And now the action caller inside componentDidMount is as follows:
componentDidMount() {
if(!this.props.dishes.loaded){
this.props.startLoadingDishes();
console.log("loading dishes from database")
}
}

How to show loader image in react?

I want to show a loading image when the user hits that particular URL and hide when API is successfully fetched the data.
I am not getting in react to show image initially where I should add code and how to hide when API response in success.
This is the action creator for fetching data.
export const fetchEvents = (requestData) => ({
type: FETCH_EVENTS,
payload: axios.get(requestData.url, fetchEventsConfig)
})
And this is the reducer for fetching data.
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_EVENTS_FULFILLED:
const oldState = Object.assign({}, state)
const response = Object.assign({}, action.payload.data)
const allResults = oldState.results.concat(response.results)
return {
...state,
...response,
results: allResults
}
}
}
I am new to this react redux so any help would be great
You can add a boolean property in your Redux state to indicate loading state. Let's call it isLoading. Set isLoading true when you dispatch FETCH_EVENTS. Set it false, when you dispatch FETCH_EVENTS_FULFILLED.
Pass value of isLoading to your React component using #connect HOF. Render a loading indicator when value is true, and content when it's false.
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_EVENTS: {
return {...state, isLoading: true}
}
case FETCH_EVENTS_FULFILLED: {
const response = action.payload.data
const results = [...state.results, ...response.results]
return {
...state,
...response,
results,
isLoading: false
}
}
case FETCH_EVENTS_FAILURE: {
return {...state, isLoading: false}
}
}
}
P.S.
Containing code inside braces after each switch/case limits scope of your const inside that block.
Write a loader file (loader.js)
import React from 'react'
import {ClipLoader} from "react-spinners";
const Loader = ({ loading, message }) => {
return loading ? (
<div className='wrapper'>
<ClipLoader
size={40}
color={"#123abc"}
loading={loading}
/>
<span className='message'>
{message}
</span>
</div>
) : null
};
export default Loader;
In Actions:
export const GET_SERVICE = '[SERVICE REQUEST] GET LIST';
export const GET_SERVICE_SUCCESS = '[SERVICE REQUEST] GET LIST SUCCESS';
export const GET_SERVICE_FAILURE = '[SERVICE REQUEST] GET LIST FAILURE';
export function getService(options) {
const request = axios.post('api/services', {options});
return (dispatch) => {
dispatch({
type: GET_SERVICE
});
try {
request.then((response) =>
dispatch({
type: GET_SERVICE_SUCCESS,
payload: {data: response.data.data, meta: response.data.meta}
})
);
} catch (e) {
dispatch({
type: GET_SERVICE_FAILURE
});
}
}
}
In Reducer:
const initialState = {
services: [],
loading: false,
hasErrors: false,
};
const serviceReducer = function (state = initialState, action) {
switch (action.type) {
case Actions.GET_SERVICE:
return {...state, loading: true};
case Actions.GET_SERVICE_SUCCESS:
return {
...state,
loading: false,
services: [...action.payload.data],
page: action.payload.meta.page,
total: action.payload.meta.total
};
case Actions.GET_SERVICE_FAILURE:
return {...state, loading: false, hasErrors: true};
default:
return state;
}
};
export default serviceReducer;
Write following code in your component:
<div className="flex flex-1 w-full">
<Loader loading={loading} />
</div>

Categories

Resources