I am trying to create a context for saveing data from an Api response. But it gives me an error.
I don't know how to solve the error.
This screen is a show screen. In the index screen I can use another context and it works well.
I want to create another context for saving data from other Api call. I am trying to copy it but it gives me an error.
Thanks.
TypeError: undefined is not an object (evaluating '_useContext.state')
CONTEXT
import createDataContext from './createDataContext';
import jsonServer from '../api/api';
const currencyPrices = (state, action) => {
switch (action.type) {
case 'show_prices':
return action.payload;
default:
return state;
}
};
const showPrices = (dispatch) => {
return async (id) => {
const response = await jsonServer.get(`/prices/${id}`);
dispatch({type: 'show_prices', payload: response.data[0]});
};
};
export const {Context, Provider} = createDataContext(
currencyPrices,
{showPrices},
[],
);
CREATE DATA CONTEXT
import React, {useReducer} from 'react';
export default (reducer, actions, initialState) => {
const Context = React.createContext();
const Provider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState);
// actions === { addBlogPost: (dispatch) => { return () => {} } }
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{state, ...boundActions}}>
{children}
</Context.Provider>
);
};
return {Context, Provider};
};
SCREEN
/* eslint-disable react-hooks/rules-of-hooks */
import React, {useContext, useEffect} from 'react';
import {View, Text} from 'react-native';
import {Context} from '../context/currencyPrices';
const showScreen = ({navigation}) => {
const {state, showPrices} = useContext(Context);
useEffect(() => {
showPrices(1);
const listener = navigation.addListener('didFocus', () => {
showPrices(1);
});
return () => {
listener.remove();
};
});
return (
<View>
<Text>{state.length}</Text>
</View>
);
};
export default showScreen;
in app.js
import {Provider as ProviderName}
<ProciderName>
<App/>
</ProviderName}
you should wrap provider in mani root like app.js
Related
My App is crashing due to the following error but i don´t have enough information for my self to solve the problem.
Render Error, Element type is invalid: expected a string (for built-in components) or a class/function (for composite components but got undefined)
Check the render method of _default
I assume it has something to do with some export or import in my code but i am not sure what is that is causing this issue.
createDataContext.js:
import React, { useReducer } from 'react';
export default (reducer, actions, initialState) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
};
BlogContext.js:
import createDataContext from './createDataContext';
const blogReducer = (state, action) => {
switch (action.type) {
case 'add_blogpost':
return [...state, { title: `Blog Post #${state.length + 1}` }];
default:
return state;
}
};
const addBlogPost = dispatch => {
return () => {
dispatch({ type: 'add_blogpost' });
};
};
export const { Context, Provider } = createDataContext(
blogReducer,
{ addBlogPost },
[]
);
IndexScreen.js:
import React, { useContext } from 'react';
import { View, Text, StyleSheet, FlatList, Button } from 'react-native';
import { Context } from '../context/BlogContext';
const IndexScreen = () => {
const { state, addBlogPost } = useContext(Context);
return (
<View>
<Text>Index Screen</Text>
<Button title="Add Post" onPress={addBlogPost} />
<FlatList
data={state}
keyExtractor={blogPost => blogPost.title}
renderItem={({ item }) => {
return <Text>{item.title}</Text>;
}}
/>
</View>
);
};
const styles = StyleSheet.create({});
export default IndexScreen;
I am having a very tough time solving this issue
So I have set a context for cart from commerce.js and want to render it on a new page.
I am able to add to cart and all.
The cart object is getting picked in one page, but it to appear in a whole new page so therefore using contexts.
import {createContext, useEffect, useContext, useReducer} from 'react'
import {commerce} from '../../lib/commerce'
//need to correct this file to be a tsx file
const CartStateContext = createContext()
const CartDispatchContext = createContext()
const SET_CART = "SET_CART"
const initialState = {
total_items: 0,
total_unique_items: 0,
line_items: []
}
const reducer = (state,action) => {
switch(action.type){
case SET_CART:
return { ...state, ...action.payload }
default:
throw new Error(`Unknown action: ${action.type}` )
}
}
export const CartProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const setCart = (payload) => dispatch({type: SET_CART, payload})
useEffect(() => {
getCart()
},[])
const getCart = async() => {
try {
const cart = await commerce.cart.retrieve()
setCart(cart)
} catch (error){
console.log("error")
}
}
return (
<CartDispatchContext.Provider value = {{setCart}}>
<CartStateContext.Provider value = {state}>
{children}
</CartStateContext.Provider>
</CartDispatchContext.Provider>
)
}
export const useCartState = () => useContext (CartStateContext)
export const useCartDispatch = () => useContext (CartDispatchContext)
my _app.tsx
const MyApp = ({ Component, pageProps }: AppProps) => (
<div>
<Web3ContextProvider>
<>
<Component {...pageProps} />
<ToastContainer
hideProgressBar
position="bottom-right"
autoClose={2000}
/>
</>
</Web3ContextProvider>
<CartProvider>
<>
<Component {...pageProps} />
</>
</CartProvider>
</div>
);
export default MyApp;
When I try to render it on the cartPage
import React from "react"
import {CartItem, CartContainer, NavigationBar } from "../components"
import {useRouter} from 'next/router'
import { useCartState, useCartDispatch } from "../context/Cart"
export const CartPage = () => {
const {setCart} = useCartDispatch()
// console.log(setCart)
const {line_items} = useCartState()
// console.log(line_items)
return(
<pre>
{JSON.stringify(line_items,null,2)}
</pre>
)
}
export default CartPage
I get the above Type error
I am not able to figure out what is going wrong. Also if you folks have any other suggestion in next how do i render the cart object in another page
When a user log to a react app, I fill data to authState object. Inside the app I fill other state objects with data. I want to clear all those states when the user logout
for example I have this provider
import { createContext, useEffect, useReducer } from "react";
import auth from "./reducers/auth";
import pendiente from "./reducers/pendiente";
import historico from "./reducers/historico";
import authInitialState from "./initialStates/authInitialState";
import pendienteInitialState from "./initialStates/pendienteInitialState";
import historicoInitialState from "./initialStates/historicoInitialState";
export const GlobalContext = createContext();
export const GlobalProvider = ({ children }) => {
const [authState, authDispatch] = useReducer(auth, [], () => {
const localData = localStorage.auth;
return localData ? JSON.parse(localData): authInitialState;
});
const [pendienteState, pendienteDispatch] = useReducer(
pendiente,
pendienteInitialState
);
const [historicoState, historicoDispatch] = useReducer(
historico,
historicoInitialState
);
useEffect(() => {
localStorage.auth = JSON.stringify(authState);
}, [authState]);
return (
<GlobalContext.Provider
value={{
authState,
authDispatch,
pendienteState,
pendienteDispatch,
historicoState,
historicoDispatch,
}}
>
{children}
</GlobalContext.Provider>
);
};
In Logout function I'm sending and action (logout) with 3 dispatchs.
const {
authState,
authDispatch,
pendienteDispatch,
historicoDispatch,
} = useContext(GlobalContext);
const handleLogout = () => {
logout(history)(authDispatch, pendienteDispatch, historicoDispatch);
};
Inside the action I send a dispatch an to every sate objcet to clear the data with it's initial state
This works fine, but I think this is not the correct way to do it
const logout = (history) => (
dispatch,
pendienteDispatch,
historicoDispatch
) => {
localStorage.removeItem("token");
dispatch({ type: LOGOUT_USER });
pendienteDispatch({ type: CLEAR_PENDIENTE_DATA });
historicoDispatch({ type: CLEAR_HISTORICO_DATA });
history.push("/");
};
¿Any ideas ?
I'm attempting to create an Auth context file which, upon app load, checks if a user is signed in.
To do this, I'm using a 'helper' function which allows me to import the initialisation of the context and just build upon that with additional functions which authorise a user.
However, upon every app load, the Context is returning as 'undefined', and it says 'evaluating _useContext.trySignIn'.
For reference, here is my Context file:
import createDataContext from './createDataContext';
import { AsyncStorage } from 'react-native';
import { navigate } from '../navigationRef';
import { Magic } from '#magic-sdk/react-native';
const m = new Magic('API_key');
const authReducer = (state, reducer) => {
switch (action.type) {
default:
return state;
}
};
const trySignIn = dispatch => async () => {
const isLoggedIn = await m.user.isLoggedIn();
if (isLoggedIn === true) {
navigate('Dashboard');
} else {
navigate('loginFlow');
}
};
export const { Provider, Context } = createDataContext (
authReducer,
{ trySignIn },
{ isLoggedIn: null }
);
Here is my 'createDataContext' file:
import React, { useReducer } from 'react';
export default (reducer, actions, defaultValue) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, defaultValue);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key].dispatch;
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
)
};
return { Context, Provider }
};
Here is my navigation file:
import { NavigationActions } from 'react-navigation';
let navigator;
export const setNavigator = (nav) => {
navigation = nav;
};
export const navigate = (routeName, params) => {
navigator.dispatch(
NavigationActions.navigate({
routeName, params
})
);
};
And finally, here is my component attempting to use my context:
import React, { useEffect, useContext } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import { Context } from '../context/AuthContext';
const LoadingScreen = () => {
const { trySignIn } = useContext(Context);
useEffect(() => {
trySignIn();
}, [])
return (
<View style={styles.mainView}>
<ActivityIndicator style={styles.indicator} />
</View>
)
}
Can anyone see why my context would be returning as 'undefined' in my component?
I am trying to create a simple application with a context provider, when running the application on my phone using Expo application, it throws an error like in this photo
here is my app.js file:
import React from 'react';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import IndexScreen from "./src/screens/IndexScreen";
import {BlogProvider} from "./src/context/BlogContext";
const navigator = createStackNavigator({
Index: IndexScreen
}, {
initialRouteName: 'Index',
defaultNavigationOptions: {
title: 'Blog List'
}
});
const App = createAppContainer(navigator);
export default () => {
return <BlogProvider><App/></BlogProvider>;
}
and the blogContext.js file:
import React, {useReducer} from 'react';
const BlogContext = React.createContext();
const reducer = (state, action) => {
switch (action.type) {
case 'add':
return [...state, `Blog post #${state.length + 1}`]
default:
return state;
}
}
export const BlogProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer,[]);
const addBlogPost = () => {
dispatch({type: 'add'})
}
return <BlogContext.Provider value={{data: state, addBlogPosts: addBlogPost}}> {children} </BlogContext.Provider>
}
export default BlogContext;
I am seeing this error only on mobile, when opening the app in the browser it doesnt show any errors
the problem was the return statement must be wrapped into parentheses like so:
import React, {useReducer} from 'react';
const BlogContext = React.createContext();
const blogReducer = (state, action) => {
switch (action.type) {
case 'add':
return [...state, `Blog post #${state.length + 1}`]
default:
return state;
}
}
export const BlogProvider = ({children}) => {
const [blogPosts, dispatch] = useReducer(blogReducer,[]);
const addBlogPost = () => {
dispatch({type: 'add'})
};
return (
<BlogContext.Provider value={{data: blogPosts, addBlogPost}}>
{children}
</BlogContext.Provider>
);
};
export default BlogContext;
I have just wasted 3 hours of my life contemplating quitting code because of this.
This might be a possible solution for someone else.
I rewrote everything and I realized that my linter added a space before and after {children}.
i.e.:
//CORRECT
return (<UserContext.Provider value={{ userAuth, userDocument }}>{children}</UserContext.Provider>);
//WRONG will give Error: Text string must be rendered...blah blah..
return (<UserContext.Provider value={{ userAuth, userDocument }}> {children} </UserContext.Provider>);