Getting undefined for useContext() hook when functional Context is used - reactjs

BookContext.js
import React, { createContext, useState } from 'react'
export const BookContext = createContext()
export default function BookContextProvider(props) {
const [books, setbooks] = useState([
{ title: 'the way of kings' , id:1 },
{ title: 'the name of the wind', id:2 },
{ title: 'the final empire', id:3 }
])
return (
<BookContext.Provider value={{books}}>
{ props.children }
</BookContext.Provider>
)
}
Booklist.js
import React, { useContext } from 'react'
import { ThemeContext } from '../contexts/ThemeContext'
import { BookContext } from '../contexts/BookContext'
export default function Booklist() {
// Object destructuring
const { isLightTheme, light, dark } = useContext(ThemeContext)
const theme = isLightTheme ? light : dark
const { books } = useContext(BookContext)
return (
<div className="book-list" style={{color: theme.syntax, background: theme.bg}}>
<ul>
<li style={{background: theme.ui}}>the way of kings</li>
<li style={{background: theme.ui}}>the name of the wind</li>
<li style={{background: theme.ui}}>the final empire</li>
</ul>
</div>
)
}
Getting undefined for useContext().
When destructered the context it throws typeerror.
TypeError: Cannot destructure property 'books' of 'Object(...)(...)' as it is undefined.
How can I solve this?

By default the context has an undefined value. You can provide an initial value to avoid this issue when the component is mounted outside the provider. The useContext hook will use the default context value when no provider is found.
export const BookContext = createContext({ books: [] });

Related

Error when using react context - Cannot destructure property

i trying to using Context on my react app
but i got error:
Uncaught TypeError: Cannot destructure property 'selected' of 'Object(...)(...)' as it is undefined.
in my InputsList file
on this line:
const { selected, setSelected } = useContext(ParamsContext);
ParamsContext:
import { createContext } from 'react';
export const ParamsContext = createContext({
selected: [],
setSelected: () => {},
textName: null,
valueName: null
});
InputParams:
import React, { useState } from 'react';
import InputsList from './InputsList';
import { ParamsContext } from './services/ParamsContext';
function InputParams(props) {
const [selected, setSelected] = useState([]);
const textName = "test";
const valueName = "test2";
return (
<div>
<ParamsContext.Provider
selected={selected}
setSelected={setSelected}
textName={textName}
valueName={valueName}>
<InputsList />
</ParamsContext.Provider>
</div>
);
}
export default InputParams;
InputsList:
import React, { useContext } from 'react';
import { ParamsContext } from './services/ParamsContext';
function InputsList(props) {
const { selected, setSelected } = useContext(ParamsContext);
return (
<div>
{selected.length}
</div>
);
}
export default InputsList;
what can i do?
Contexte.Provider accept a value props,
And should be used like:
<ParamsContext.Provider value={{selected, setSelected, textName, valueName}}>
<\ParamsContext.Provider>
Provider accept a value prop, in your case, an object. So it should be:
<ParamsContext.Provider
value={{
selected,
setSelected,
textName,
valueName
}}
>
<InputsList />
</ParamsContext.Provider>
See docs

Can't access state using 'useStoreState in react easy-peasy

I recently decided to learn about state management with easy-peasy, and followed along the basic tutorials, but i can't seem to access the state.
Here is the App component :-
import model from './model';
import Todo from './components/Todo.tsx';
import { StoreProvider, createStore } from 'easy-peasy';
const store = createStore(model);
function App() {
return (
<StoreProvider store={store}>
<div className="App">
<Todo />
</div>
</StoreProvider>
);
}
export default App;
Here is the model file 'model.js'
export default {
todos: [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
};
And this is the Todo file:-
import React from 'react';
import {useStoreState } from 'easy-peasy';
const Todo = () => {
//The line below does not work for me, when i do 'state.todos' i get an error that todos does not exist on type
const todos = useStoreState(state=>state.todos);
return (
<div>
</div>
);
}
export default Todo;
Try removing the .todos so that
const todos = useStoreState(state=>state.todos);
turns into:
const todos = useStoreState(state=>state);
import React from 'react'
import { useStoreState } from 'easy-peasy';
import Feed from './Feed'
const Home = ({isLoading,fetchError}) => {
const { searchResults} = useStoreState((state)=>state.searchResults)
return (
{isLoading && Loading Posts ...};
{fetchError && <p className='statusMsg' style={{ color: "red" }}>{ fetchError }};
{!isLoading && !fetchError && (searchResults.length ? : No posts to display)}
)
}
export default Home;

Error: Objects are not valid as a React child (found: object with keys {})

I'm a beginner learning ts for the first time. Thank you in advance for sharing your knowledge. I am making a to-do list. I used to react to complete it. But now I am using react and typescript together to complete the code.
I got an error. I don't know what the problem is. Help me, please.
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
Click here to view the full code
What I think that the problem is this file.
// contet.tsx
import React, { createContext, useReducer, useContext, Dispatch } from 'react';
import reducer from "./reducer";
import { Action } from './actions'
export interface ITodo {
id: string;
text: string;
};
export interface State {
toDos: ITodo[];
completed: ITodo[];
}
interface ContextValue {
state: State;
dispatch: Dispatch<Action>;
}
export const initialState = {
toDos: [],
completed: [],
};
const ToDosContext = createContext<ContextValue>({
state: initialState,
dispatch: () => { console.error("called dispatch outside of a ToDosContext Provider") }
});
export const ToDosProvider = ({ children }: { children: React.ReactNode }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<ToDosContext.Provider value={{ state, dispatch }}>
{children}
</ToDosContext.Provider>
);
};
export const useTodosState = (): State => {
const { state } = useContext(ToDosContext);
return state;
};
export const useTodosDispatch = (): Dispatch<Action> => {
const { dispatch } = useContext(ToDosContext);
return dispatch;
};
This is App.tsx
import React from "react";
import Add from "./Add";
import Title from "./Title";
import Progress from "./Progress";
import List from "./List";
import ToDo from "./ToDo";
import styled from "styled-components";
import { useTodosState } from '../context';
const App = () => {
const { toDos, completed } = useTodosState();
console.log(toDos);
return (
<Title>
<Add />
<Progress />
<Lists>
<List title={toDos.length !== 0 ? "To Dos" : ""}>
{toDos.map((toDo) => (
<ToDo key={toDo.id} id={toDo.id} text={toDo.text} isCompleted={false} />
))}
</List>
<List title={completed.length !== 0 ? "Completed" : ""}>
{completed.map((toDo) => (
<ToDo key={toDo.id} id={toDo.id} text=
{toDo.text} isCompleted />
))}
</List>
</Lists>
</Title >
)
}
export default App;
I had a look at the repo you shared the problem is at List.tsx component and the way you are trying to access your props from your components. It should be
const List = ({ title, children }: any) => (
instead of
const List = (title: any, children: any) => (
as in react functional components take only one parameter the props object.
Also if you want to add types there you could do {title:string; children: ReactElement| ReactElement[]}
I think it has being a better way for this situation. You can use PropsWithChildren you can check it out for details.
for little example
export interface SearchProps {
height: number
}
function Search({ children }: PropsWithChildren<SearchProps>) {
..
..
return()
}

Could not find "store" in the context of "Connect(Component)" GatsbyJs Redux

I ran into some issues with my Gatsby web application when trying to implement a store for global states with Redux. I am new to both. Before I worked with MobX and "plain" React.
The problem is, that I cannot access the data of my store from my components. I use the Redux Provider class as I read in several tutorials, but as I make use of other providers as well, my case seems to be special... This is what I came up with so far:
gatsby-ssr.js and gatsby-browser.js
import prepPages from "./prepPages"
export const wrapRootElement = prepPages
prepPages.js
import React from "react"
import { createGlobalStyle, ThemeProvider } from "styled-components"
import { Provider } from "react-redux"
import createStore from "./src/state/store"
import { MDXProvider } from "#mdx-js/react"
import { Table } from "./src/components"
import Theme from "./src/themes/theme"
//Provider for my global styling
const GlobalStyles = createGlobalStyle`...`
//Overriding the table component
const components = {
table: Table
}
export default ({ element }) => {
const store = createStore()
return(
<Provider store={store}>
<MDXProvider components={components}>
<ThemeProvider theme={Theme}>
<GlobalStyles/>
{element}
</ThemeProvider>
</MDXProvider>
</Provider>
)
}
store.js
import {createStore as reduxCreateStore} from "redux"
const initialState = {
loggedIn: false,
menuToggleOn: false,
//other initial states
}
const reducer = (state, action, dispatch) => {
//Toggles
if(action.type === 'TOGGLE_MENU'){
return {
...state,
toggleMenuOn: !state.toggleMenuOn
}
}
//other actions
}
const createStore = () => reduxCreateStore(reducer, initialState);
export default createStore;
components/Nav.js
import React from 'react';
import {useStaticQuery, Link, graphql} from "gatsby";
import {NavWrapper} from "../styles";
import { Button } from "./Button";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import {faBars} from "#fortawesome/free-solid-svg-icons";
import connect from "react-redux/lib/connect/connect";
import PropTypes from "prop-types"
const NavHolder = ({loggedIn, toggleMenu, toggleMenuOn}) => {
...
//defining the nav items depending on the login state
var items;
var cta = {};
if(loggedIn){
items = [
{name: "home", ref: "/", key: 0},
{name: "wiki", ref: "/wiki", key: 1},
{name: "workspace", ref: "/workspace", key: 2}
]
}else {
items = [
{name: "about", ref: "#about", key: 0},
{name: "features", ref: "#features", key: 1},
{name: "download", ref: "#download", key: 2},
{name: "contact", ref: "#contact", key: 3}
];
cta = {exists: true, name: "login"}
}
//mapping the nav items and adding the visible class if the menu is toggled on
let navItems = items.map((item) =>
<li key={item.key} className={toggleMenuOn ? "nav-item visible" : "nav-item"}>
<a href={item.ref} className={isActive ? "active":""}>
{item.name}
</a>
</li>
)
return (
<NavWrapper>
<ul>
<li>
<Link to="/" id="logo">...</Link>
</li>
{navItems}
<li className="nav-toggle">
<a href="/" onClick={toggleMenu}>
<FontAwesomeIcon icon={faBars}/>
</a>
</li>
{cta.exists && (
<li className="nav-cta">
<Button color="petrol" href="login">{cta.name}</Button>
</li>
)}
</ul>
</NavWrapper>
)
}
NavHolder.propTypes = {
loggedIn: PropTypes.bool.isRequired,
menuToggleOn: PropTypes.bool.isRequired,
toggleMenu: PropTypes.func.isRequired
}
const mapStateToProps = ({loggedIn, toggleMenuOn}) => {
return { loggedIn, toggleMenuOn }
}
const mapDispatchToProps = dispatch => {
return { toggleMenu: () => dispatch({ type: `TOGGLE_MENU` }) }
}
const ConnectedNav = connect(mapStateToProps, mapDispatchToProps)(NavHolder)
export const Nav = () => {
return <ConnectedNav/>
}
I thought this might work, but I get this error:
Error: Could not find "store" in the context of "Connect(NavHolder)". Either wrap the root component in a Provider, or pass a custom React context provider to Provider and the corresponding React context consumer to Connect(NavHolder) in connect options.
could not find store in component error
Has anyone an idea where I went wrong? I am really grateful for any help.
Thanks :)
With Gatsby you need to use wrapRootElement API.
Wrap the root element in your Gatsby markup once using wrapRootElement, an API supporting both Gatsby’s server rendering and browser JavaScript processes.
Refer to Adding a Redux Store in Gatsby docs, there is an example repo for that.

TypeError: Invalid attempt to destructure non-iterable instance with CONTEXT API value state on reactjs

Hi i try to make a simply state managment with context api and hooks on react js.
I have a context named UIcontext and one component container called home.
when i do the new instance of useUIcontextStateValue in home, the app crash and throw this error
TypeError: Invalid attempt to destructure non-iterable instance
I have no idea this is happen, in other app i have the same code and work, please help friend.
this is the context
import React , {createContext, useContext, useReducer} from 'react';
export const UIcontext = createContext();
export const UIcontextProvider = ({reducer, initialState, children}) => {
return (
<UIcontext.Provider>
{children}
</UIcontext.Provider>
);
};
export const useUIcontextStateValue = () => useContext(UIcontext);
and this is the component where i use it
import React, {useEffect, useState} from 'react';
import { UIcontextProvider, useUIcontextStateValue } from '../../Store/UiContext';
import { Header, Logo, LandingModule, Menu } from '../../Components';
const Home = props => {
const [showHeader, setShowHeader] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const [{ submenu }, dispatch] = useUIcontextStateValue();
const initialState = {
submenu: false
};
const reducer = (state, action) => {
switch (action.type) {
case 'toogleSubmenu':
return {
...state,
submenu: action.submenuState
};
default:
return state;
}
};
useEffect(()=>{
window.onscroll = function() {
if(window.pageYOffset === 0) {
setShowHeader(false);
} else {
setShowHeader(true);
}
}
});
const toogleMenu = () => {
console.log("ANTES", menuOpen);
setMenuOpen(!menuOpen);
console.log("DESPUES", menuOpen);
};
return (
<UIcontextProvider>
<section className="home" >
<Header show={showHeader}/>
<Menu open={menuOpen}/>
<section name="landing" className="home__landing" >
<Logo/>
<div className="home__landing__container-text">
<h1>Welcome</h1>
<div>
<h5><span>TO ADAM'S GRAY</span><br></br> WEBSITE</h5>
<div></div>
</div>
</div>
</section>
<LandingModule
title="HELLA SLINGSHOTS"
subtitle="In this project I make over 35,000 slingshot each year in a variety of colors and designs."
titleBg={hellaBG}
productBg={hellaProductBG}
color='#00c691'
/>
<LandingModule
title="BICYCLE BOLTS"
subtitle="Here i make and sell metric security bolts to help
keep components on your bicycle safe from
opportunistic thievery."
titleBg={bicycleBG}
productBg={bicycleProductBG}
color='#6140FF'
/>
<LandingModule
title="SURF BRAIN"
subtitle="In this project I make over 35,000 slingshot each year in a variety of colors and designs."
titleBg={hellaBG}
productBg={hellaProductBG}
color='#2AD9B1'
/>
</section>
</UIcontextProvider>
);
};
export default Home;

Resources