Context returning undefined - useContext - javascript

I'm trying to set up useContext in the simplest way possible, but it keeps returning undefined.
I've checked it several times but still can't decipher what I'm missing.
Context.js:
import React from 'react';
export const Context = React.createContext();
export function Provider(props) {
const sayHi = () => {
console.log('hi')
}
const value = {
actions: {
sayHi
}
}
return(
<Context.Provider value={value}>
{props.children}
</Context.Provider>
);
}
Consumer component (Transfer.js):
import React, { useContext } from 'react';
import { Context } from '../Context';
function Transfer() {
const value = useContext(Context);
console.log(value); // ------> returns undefined
console.log(Context); // ----> it is defined
return (
<div className="send">
// some HTML
</div>
);
}
export default Transfer;
Folder structure:
src
└───components
│ └─── Transfer.js
│
└───App.js
└───App.scss
└───Context.js
...

Answer: Missing Provider on root component

Hi #cdgmachado : The issue is due to an empty value when you're creating context value instead use this :
export const Context = React.createContext(null)
This where i've read about it .
https://kentcdodds.com/blog/how-to-use-react-context-effectively .
You can look my codesandbox also :
https://codesandbox.io/s/goofy-bash-z1cnq?file=/src/Context.js:28-76
From the blog : This a capture of the part talking about :
Hope that it'll solve it

Related

Can't update state in Context

EDIT BELOW
I'm trying to migrate my states to some contexts so I don't have to constantly prop drill. The problem is, state won't update in the context. I just want a single value in state to be changed to true on click.
Here is my projectTile.js
import React, {useContext} from 'react';
import {ProjectContext, ProjectProvider} from './ProjectContext.js';
import {ProjectFunctionsContext, ProjectFunctionsProvider} from './projectFunctionsContext';
// profpic is going to be pulled from the logged in user, for demonstration purposes I just have it pulling the default profile picture right now
import profpic from '../../icon.png';
// projectImage will be passed from the project component, for now it's just a default chosen from the directory.
import defaultProjectImage from '../../defaultProject.jpg';
const ProjectTile = ({projectAuthorName, projectTitle, projectImage,setSavedProjectData}) => {
const [projects, setProjects] = useContext(ProjectContext);
const [projectClicked, setProjectClicked] = useContext(ProjectFunctionsContext);
// Console Log to try to figure out where any errors are coming from, if they arise.
console.log('Project Author: ' + projectAuthorName + " \n Project Title: " + projectTitle + " \n Project Image: " + projectImage);
// In this return statement, we build the project tile out of the elements that we're getting from the ProjectContext
console.log('projectClicked is doing this: ' + projectClicked);
return (
<div className="ProjectTile__container" onClick={() => {setProjectClicked(true); console.log(projectClicked);setSavedProjectData({projectAuthorName: projectAuthorName})}}>
<img src={defaultProjectImage /*projectImage -- this is commented out because it doesn't work at the moment*/} className="ProjectTile__Img" alt="Placeholder"/>
<div className="ProjectTile__overlay" >
<img src={profpic} className="ProjectTile__icon" alt="Profile"/>
<div className="ProjectTile__text">
{projectTitle}
<br></br>
{projectAuthorName}
</div>
</div>
</div>
);
}
export default ProjectTile;
Here is my projectFunctionsContext.js
import React, {useState, createContext} from 'react';
export const ProjectFunctionsContext = createContext();
export const ProjectFunctionsProvider = (props) => {
const [projectClicked, setProjectClicked] = useState(false);
return(
<ProjectFunctionsContext.Provider
value={[projectClicked,setProjectClicked]}
>
{props.children}
</ProjectFunctionsContext.Provider>
);
}
It just won't update projectClicked to true, what am I doing wrong?
EDIT:
Called the context in parent of this component, making it reset the state.
It happens to work with only one call to get those variables.
You need to set the values object in your ContextProvider which allows you to access the properties in your components with the useContext hook.
Your provider should look like this:
const contextValue = {
projectClicked,
setProjectClicked
};
<ProjectFunctionsContext.Provider value={contextValue}>
{props.children}
</ProjectFunctionsContext.Provider>
Then in your components use the useContext hook to retrieve the values stored in context:
const { projectClicked, setProjectClicked } = useContext(ProjectFunctionsContext);

call react component-element as variable

Is it possible to call a React component element with a variable inside?
import React from "react"
/*React functional component*/
function someName() {
const someVar = "componentName"; //the name of the called component
return(
<{someVar}/>
)
}
export default someName;
I try to implement this in a router and to change the filenames(Sites) (in the element) dynamically with useState from fetched data.
I am open to all kind of help :)
There is no direct way to do that but you can use this approach.
import ComponentA from '...path';
import ComponentB from '...path';
...
const components = {
componentA: ComponentA,
componentB: ComponentB,
...
}
...
function App(props) {
const TargetComponent = components[props.componentName];
return <TargetComponent />;
}

Use imported variable as a dinamic prop in React

Sorry for the noob question, but I'm a noob in React and I am strugling with this.
I have a file that exports a variable that is being mutated over time. Let's say something like this (not the real code, the variable is changing correctly):
// variable.js
let myVar = 0;
setInterval(() => myVar++, 3000);
export { myVar };
and a react component that has to display the current value:
import React, { Component, Fragment } from "react";
import { myVar } from './variable.js';
export default class myComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Fragment>
<div>{myVar}</div>
</Fragment>
);
}
}
What would be the best approach to get the variable displayed correctly while they change? I have tryied to set is as a state, as a prop and rendering it directly, but I am missing something.
I can not export a getter function, as I don't know from the component when the variable is going to change, but maybe I can change the approach? maybe throwing an event in each change?
Try this, It won't work like the real-time update. But you can access like below
You can create a custom hook, that will update real-time
export default function useUpdate() {
const [myVar, setState] = useState(0)
setTimeout(function () {
setState(myVar++);
}, 3000);
return [myVar, setState];
}
import React, { Component, Fragment } from "react";
import { useUpdate } from './variable.js';
export default () => {
const [myVar] = useUpdate();
return (
<Fragment>
<div>{myVar}</div>
</Fragment>
);
}

How to use multiple global states using the same Context in React Native?

I'm developing a Mobile Application using React Native. I came up with a thought of, is it possible to use multiple global states using the same Context.
So, I implemented a context like this.
// GlobalStateContext.js
import React, { createContext, useContext, useEffect } from 'react';
const GlobalStateContext = createContext({ globalStateValue: null, setGlobalStateValue: () => {} });
export function useGlobalState (initialValue = null) {
const { globalStateValue, setGlobalStateValue } = useContext(GlobalStateContext);
useEffect(() => { setGlobalStateValue(initialValue) }, []);
return [globalStateValue, setGlobalStateValue];
}
export default function GlobalStateContextProvider (props) {
const { value, children } = props;
return (
<GlobalStateContext.Provider value={value} >
{children}
</GlobalStateContext.Provider>
)
}
In my App.js, I've wrapped my App with the GlobalStateContextProvider.
// App.js
import GlobalStateContextProvider from './path/to/GlobalStateContext';
export default function App() {
const [globalStateValue, setGlobalStateValue] = useState(null);
return (
<GlobalStateContextProvider value={{ globalStateValue, setGlobalStateValue }} >
// <MyAppContent />
</GlobalStateContextProvider>
)
}
Then, I tried to do something like this on some of my screen files.
import { useGlobalState } from '../path/to/GlobalStateContext';
const [myState1, setMyState1] = useGlobalState('State 01');
const [myState2, setMyState2] = useGlobalState('State 02');
But, there are NO TWO SEPARATE global states. I know there should do something more in the implementation if it is possible to achieve what I want.
So, is this thing is possible? When using useState hook, we can do like,
const [myState1, setMyState1] = useState('State 01');
const [myState2, setMyState2] = useState('State 02');
In this case, we have TWO SEPARATE local states.
Like this, I want to know if it is possible to define some GLOBAL STATES and use them.

How to provide and consume context in the same component?

I'm using react context api for my game app and I created a GameContext.js
import React, { useState, createContext } from 'react';
const GameContext = createContext();
const GameProvider = ({ children }) => {
const [startgame, setStartgame] = useState(false);
return (
<GameContext.Provider value={[startgame, setStartgame]}>
{children}
</GameContext.Provider>
);
};
export { GameContext, GameProvider };
And in the App.js I provide the context.
import { GameProvider, GameContext } from './context/GameContext';
const App = () => {
console.log(useContext(GameContext), 'Gamecontext');
return (
<GameProvider>
<div className="App">
{!startgame ? <WelcomeScreen />
: <GameScreen />}
</div>
</GameProvider>
);
};
export default App;
This doesnt work because startgame is not accessible in App.js.
Also, I noticed the useContext(GameContext) is undefined. I want to use the startgame value in App.js, but I cant destructure an undefined value.
How can one provide and consume the context in the same component App.js? Is this the right way or am missing something?
You need to use Context.Consumer component instead of useContext hook. Because when you provide a context, it will be consumable via useContext hook or this.context only within its children not parent. In that case you need to use MyContext.Consumer component.
import { GameProvider, GameContext } from './context/GameContext';
const App = () => {
return (
<GameProvider>
<div className="App">
<GameContext.Consumer>
{(ctx) => (!ctx.startgame ? <WelcomeScreen /> : <GameScreen />)}
</GameContext.Consumer>
</div>
</GameProvider>
);
};
export default App;
From React docs:
Consumer - Requires a function as a child. The function receives the current context value and returns a React node. The value argument passed to the function will be equal to the value prop of the closest Provider for this context above in the tree. If there is no Provider for this context above, the value argument will be equal to the defaultValue that was passed to createContext().

Categories

Resources