React useContext: State is displaying undefined - javascript

I'm passing the value of my state using useContext. However it keeps on saying that "toggle" is undefined how do i solved this part that the value of toggle can be passed to mainSection?
Here's my code
import React, { useState, createContext } from 'react';
import ReactDOM from 'react-dom';
const languages = ['JavaScript', 'Python'];
export const reactContext = React.createContext()
function App() {
const [toggle,setToggle] = useState(false)
// implement Context here so can be used in child components
return (
<reactContext.Provider value={{toggle,setToggle}}>
<MainSection />
</reactContext.Provider >
);
}
function MainSection() {
console.log(toggle)
return (
<div>
<p id="favoriteLanguage">Favorite programing language: {languages[0]}</p>
<button id="changeFavorite" onClick={() => console.log(toggle)}>Toggle language</button>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);

you are missing useContext. At the same time you should likely use ReactContext instead of reactContext.
function MainSection() {
const { toggle, setToggle } = useContext(reactContext) // <-- you are missing this line
console.log(toggle)
return (
<div>
<p id="favoriteLanguage">Favorite programing language: {languages[0]}</p>
<button id="changeFavorite" onClick={() => console.log(toggle)}>Toggle language</button>
</div>
)
}
Docs - https://reactjs.org/docs/hooks-reference.html#usecontext

Related

(REACT JS) put value on 1 array element from component

I'm trying to give one component the array value at a certain index and assign a value that i want from the child component.
I want it like this because I'm trying to do a survey app and the number of question can be different. this is just a little test that concludes what I want.
the base Component
import React, { useState } from 'react';
import './style.css';
import Comp from './Component.js';
export default function App() {
const [results, setResults] = useState([]);
results.length = 20;
results[3] = 'kiss';
results[2] = [12, 454, 45];
console.log(results);
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Comp result={results[5]}/>
<button onClick={() => console.log(results)}> SHOW </button>
</div>
);
}
the component
import React, { useState } from 'react';
const Comp = ({result}) => {
result = 1
console.log(result)
return (
<div>
hhhhh
</div>
);
}
export default Comp
here is a place I set it up => https://stackblitz.com/edit/react-mfpk5f?file=src%2FApp.js,src%2FComponent.js
every suggestion is highly appreciated!
parent componentHere i have tried a way to find solution ,
just keep a callback function in child component and call a function of parent component inside child so that u can pass data to it .
child component
If you want to add more, you use the setResults() e.g. setResults(['kiss']); so now your results='kiss', if you want more is setResults(...results,[12, 454, 45]); and now your results= kiss,12,454,45 . But:
import React, { useState } from 'react';
import './style.css';
import Comp from './Component.js';
export default function App() {
const [results, setResults] = useState(['hiii']);
function handleClick() {
const array1 = 'kiss';
const array2 = [12, 454, 45];
setResults([...results, array1, array2]);
console.log(results);
}
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Comp result={results[5]} />
<button onClick={() => handleClick()}> SHOW </button>
</div>
);
}
First you need to add the values when something happened, e.g. onClick={...}.
<Comp result={results[5]}/> this is correct, but you call when the result=[] show you need to call after updating, e.g.
import React, { useState } from 'react';
import './style.css';
import Comp from './Component.js';
export default function App() {
const [results, setResults] = useState(['Hi']);
function handleClick() {
const array1 = 'kiss';
const array2 = [12, 454, 45];
setResults([...results, array1]);
console.log(results);
}
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Comp result={results} />
<button onClick={() => handleClick()}> {results} </button>
<div>
{results.map(() => {
return <Comp result={results[5]} />;
})}
</div>
</div>
);
}
Of course this is NOT the best solution, but I hope you understand what happened, and like you will see you need to press the button 5 times to get something for the results[5] <Comp result={results[5]} />
and for the last you need to change the Comp:
import React, { useState } from 'react';
const Comp = ({result}) => {
const [compResults, setcompResults] = useState(result);
console.log(compResults)
return (
<div>
{compResults}
</div>
);
}
export default Comp

getting problem on using useContext in react?

I have a simple react app in which i have to use useContext.
(btw im using vite + react)
here is my code for Context.jsx
import React, {useContext} from 'react';
const emailContext = React.createContext();
export const useEmail = () => useContext(emailContext);
export const emailProvider = ({children}) => {
const currentUser = "None";
const value = {
currentUser
}
return(
<emailContext.Provider value={value}>
{children}
</emailContext.Provider>
)
}
and heres how i am using the context
import "./styles.css";
import { useEmail } from "./Context/Context"
export default function App() {
const {currentUser} = useEmail();
return (
<div className="App">
<h1>Hello CodeSandbox {currentUser}</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
I am sure why I am getting error in this code.
some of the errors that I am getting
_useEmail is undefined (latest)
currentUser user is undefined
thing i have tried
Initialized createContext with some initial value (only intial value is visible).
using useContext() directy in the App.js (useContext(emailContext) return undefined)
instead of {children} used <children/>.
used useState instead of const currentUser in emailProvider
I am getting same problem even when I use typescript.
but none of the above helped.
You should wrapping app with <emailProvider></emailProvider> to using data in value={value}. Now it gets undefined from const emailContext = React.createContext();
Below code may help you analyse the flow , also check link for more details https://medium.com/technofunnel/usecontext-in-react-hooks-aa9a60b8a461
use useContext in receiving end
import React, { useState } from "react";
var userDetailContext = React.createContext(null);
export default function UserDetailsComponent() {
var [userDetails] = useState({
name: "Mayank",
age: 30
});
return (
<userDetailContext.Provider value={userDetails}>
<h1>This is the Parent Component</h1>
<hr />
<ChildComponent userDetails={userDetails} />
</userDetailContext.Provider>
);
}
function ChildComponent(props) {
return (
<div>
<h2>This is Child Component</h2>
<hr />
<SubChildComponent />
</div>
);
}
function SubChildComponent(props) {
var contextData = React.useContext(userDetailContext);
return (
<div>
<h3>This is Sub Child Component</h3>
<h4>User Name: {contextData.name}</h4>
<h4>User Age: {contextData.age}</h4>
</div>
);
}

How to trigger child component function

I am trying to reducing my code complexity to express by defining just skeleton code bellow. have to trigger the toggleModel of the child component
import React, { useState } from "react";
import "./styles.css";
const ChildComponent = (props) => {
// .... some useStates
const toggleModel = () => {
// have to trigger this methoud once user clicks on button
// have to change some states here
};
return (
<div>
{props.children}
...... other things .......
</div>
);
};
export default function ParentComponet() {
return (
<div className="App">
Hello
<ChildComponent>
<button
type="button"
onClick={() => {
// here i have to trigger the toggleModel function of ChildComponent
}}
>
Toggle Model
</button>
</ChildComponent>
</div>
);
}
i am rendering child component by sending children elements, have to trigger the toggleModel of the child component it will reduce my 70 % redundant code at our application. is there any way to achieve the same codesandbox. Thank you in advance
You can use useState and useEffect to pass state down and react to it.
import React, { useState } from "react";
import "./styles.css";
const ChildComponent = ({visible, children, setVisible}) => {
React.useEffect(() => {
const toggleModel = () => {
alert('Visible changes to ' + visible )
};
toggleModel()
}, [visible])
return <div>{children}</div>;
};
export default function ParentComponet() {
const [visible, setVisible] = React.useState(false)
return (
<div className="App">
Hello
<ChildComponent visible={visible} setVisible={setVisible}>
<button
type="button"
onClick={()=> setVisible(!visible)}
>
Toggle Model
</button>
</ChildComponent>
</div>
);
}
https://codesandbox.io/s/objective-ramanujan-j3eqg
The alternative is use #yaiks answer.
You can take a look at this question here, it can help you.
But I would say it's not a good practice to call a child function from the parent. Usually what I would do is to "lift up" the method to the parent, and pass down to the child if possible.
Here is another way to call your ChilComponent's function - using forwardRef:
import React, { useState, useImperativeHandle, forwardRef } from "react";
import "./styles.css";
const ChildComponent = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
toggleModel() {
alert("alert from ChildComponent");
}
}));
return <div>{props.children}</div>;
});
export default function ParentComponet() {
return (
<div className="App">
Hello
<ChildComponent ref={ChildComponent}>
<button
type="button"
onClick={() => ChildComponent.current.toggleModel()}
>
Toggle Model
</button>
</ChildComponent>
</div>
);
}
Sandbox: https://codesandbox.io/s/pensive-jones-lw0pf?file=/src/App.js
My answer is courtesy of #rossipedia: https://stackoverflow.com/a/37950970/1927991

How can I change this class base higher order component into a functional component?

I have already created a HOC in my react app following this, and its working fine. However i was wondering if there is a way to create a HOC as functional component(With or without state)??? since the given example is a class based component.
Tried to find the same over web but couldn't get anything. Not sure if thats even possible?? Or right thing to do ever??
Any leads will be appreciated :)
I agree with siraj, strictly speaking the example in the accepted answer is not a true HOC. The distinguishing feature of a HOC is that it returns a component, whereas the PrivateRoute component in the accepted answer is a component itself. So while it accomplishes what it set out to do just fine, I don't think it is a great example of a HOC.
In the functional component world, the most basic HOC would look like this:
const withNothing = Component => ({ ...props }) => (
<Component {...props} />
);
Calling withNothing returns another component (not an instance, that's the main difference), which can then be used just like a regular component:
const ComponentWithNothing = withNothing(Component);
const instance = <ComponentWithNothing someProp="test" />;
One way to use this is if you want to use ad-hoc (no pun intended lol) context providers.
Let's say my application has multiple points where a user can login. I don't want to copy the login logic (API calls and success/error messages) across all these points, so I'd like a reusable <Login /> component. However, in my case all these points of login differ significantly visually, so a reusable component is not an option. What I need is a reusable <WithLogin /> component, which would provide its children with all the necessary functionality - the API call and success/error messages. Here's one way to do this:
// This context will only hold the `login` method.
// Calling this method will invoke all the required logic.
const LoginContext = React.createContext();
LoginContext.displayName = "Login";
// This "HOC" (not a true HOC yet) should take care of
// all the reusable logic - API calls and messages.
// This will allow me to pass different layouts as children.
const WithLogin = ({ children }) => {
const [popup, setPopup] = useState(null);
const doLogin = useCallback(
(email, password) =>
callLoginAPI(email, password).then(
() => {
setPopup({
message: "Success"
});
},
() => {
setPopup({
error: true,
message: "Failure"
});
}
),
[setPopup]
);
return (
<LoginContext.Provider value={doLogin}>
{children}
{popup ? (
<Modal
error={popup.error}
message={popup.message}
onClose={() => setPopup(null)}
/>
) : null}
</LoginContext.Provider>
);
};
// This is my main component. It is very neat and simple
// because all the technical bits are inside WithLogin.
const MyComponent = () => {
const login = useContext(LoginContext);
const doLogin = useCallback(() => {
login("a#b.c", "password");
}, [login]);
return (
<WithLogin>
<button type="button" onClick={doLogin}>
Login!
</button>
</WithLogin>
);
};
Unfortunately, this does not work because LoginContext.Provider is instantiated inside MyComponent, and so useContext(LoginContext) returns nothing.
HOC to the rescue! What if I added a tiny middleman:
const withLogin = Component => ({ ...props }) => (
<WithLogin>
<Component {...props} />
</WithLogin>
);
And then:
const MyComponent = () => {
const login = useContext(LoginContext);
const doLogin = useCallback(() => {
login("a#b.c", "password");
}, [login]);
return (
<button type="button" onClick={doLogin}>
Login!
</button>
);
};
const MyComponentWithLogin = withLogin(MyComponent);
Bam! MyComponentWithLogin will now work as expected.
This may well not be the best way to approach this particular situation, but I kinda like it.
And yes, it really is just an extra function call, nothing more! According to the official guide:
HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.
Definitely you can create a functional stateless component that accepts component as an input and return some other component as an output, for example;
You can create a PrivateRoute component that accepts a Component as a prop value and returns some other Component depending on if user is authenticated or not.
If user is not authenticated(read it from context store) then you redirect user to login page with <Redirect to='/login'/>else you return the component passed as a prop and send other props to that component <Component {...props} />
App.js
const App = () => {
return (
<Switch>
<PrivateRoute exact path='/' component={Home} />
<Route exact path='/about' component={About} />
<Route exact path='/login' component={Login} />
<Route exact path='/register' component={Register} />
</Switch>
);
}
export default App;
PrivateRoute.jsx
import React, { useContext , useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom'
import AuthContext from '../../context/auth/authContext'
const PrivateRoute = ({ component: Component, ...rest }) => {
const authContext = useContext(AuthContext)
const { loadUser, isAuthenticated } = authContext
useEffect(() => {
loadUser()
// eslint-disable-next-line
}, [])
if(isAuthenticated === null){
return <></>
}
return (
<Route {...rest} render={props =>
!isAuthenticated ? (
<Redirect to='/login'/>
) : (
<Component {...props} />
)
}
/>
);
};
export default PrivateRoute;
Higher Order Components does not have to be class components, their purpose is to take a Component as an input and return a component as an output according to some logic.
The following is an over simplified example of using HOC with functional components.
The functional component to be "wrapped":
import React from 'react'
import withClasses from '../withClasses'
const ToBeWrappedByHOC = () => {
return (
<div>
<p>I'm wrapped by a higher order component</p>
</div>
)
}
export default withClasses(ToBeWrappedByHOC, "myClassName");
The Higher Order Component:
import React from 'react'
const withClasses = (WrappedComponent, classes) => {
return (props) => (
<div className={classes}>
<WrappedComponent {...props} />
</div>
);
};
export default withClasses;
The component can be used in a different component like so.
<ToBeWrappedByHOC/>
I might be late to the party but here is my two-cent regarding the HOC
Creating HOC in a true react functional component way is kind of impossible because it is suggested not to call hook inside a nested function.
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in-depth below.)
Rules of Hooks
Here is what I have tried and failed
import React, { useState } from "react";
import "./styles.css";
function Component(props) {
console.log(props);
return (
<div>
<h2> Component Count {props.count}</h2>
<button onClick={props.handleClick}>Click</button>
</div>
);
}
function Component1(props) {
console.log(props);
return (
<div>
<h2> Component1 Count {props.count}</h2>
<button onClick={props.handleClick}>Click</button>
</div>
);
}
function HOC(WrapperFunction) {
return function (props) {
const handleClick = () => {
setCount(count + 1);
};
const [count, setCount] = useState(0);
return (
<WrapperFunction handleClick={handleClick} count={count} {...props} />
);
}
}
const Comp1 = HOC((props) => {
return <Component {...props} />;
});
const Comp2 = HOC((props) => {
return <Component1 {...props} />;
});
export default function App() {
return (
<div className="App">
<Comp1 name="hel" />
<Comp2 />
</div>
);
}
CodeSandBox
Even though the code works in codesandbox but it won't run in your local machine because of the above rule, you should get the following error if you try to run this code
React Hook "useState" cannot be called inside a callback
So to go around this I have done the following
import "./styles.css";
import * as React from "react";
//macbook
function Company(props) {
return (
<>
<h1>Company</h1>
<p>{props.count}</p>
<button onClick={() => props.increment()}>increment</button>
</>
);
}
function Developer(props) {
return (
<>
<h1>Developer</h1>
<p>{props.count}</p>
<button onClick={() => props.increment()}>increment</button>
</>
);
}
//decorator
function HOC(Component) {
// return function () {
// const [data, setData] = React.useState();
// return <Component />;
// };
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<Component count={this.state.count} increment={this.handleClick} />
);
}
}
return Wrapper;
}
const NewCompany = HOC(Company);
const NewDeveloper = HOC(Developer);
export default function App() {
return (
<div className="App">
<NewCompany name={"Google"} />
<br />
<NewDeveloper />
</div>
);
}
CodeSandbox
I think for functional component this works fine
import {useEffect, useState} from 'react';
// Target Component
function Clock({ time }) {
return <h1>{time}</h1>
}
// HOC
function app(C) {
return (props) => {
const [time, setTime] = useState(new Date().toUTCString());
useEffect(() => {
setTimeout(() => setTime(new Date().toUTCString()), 1000);
})
return <C {...props} time={time}/>
}
}
export default app(Clock);
You can test it here: https://codesandbox.io/s/hoc-s6kmnv
Yes it is possible
import React, { useState } from 'react';
const WrapperCounter = OldComponent =>{
function WrapperCounter(props){
const[count,SetCount] = useState(0)
const incrementCounter = ()=>{
SetCount(count+1)
}
return(<OldComponent {...props} count={count} incrementCounter={incrementCounter}></OldComponent>)
}
return WrapperCounter
}
export default WrapperCounter
import React from 'react';
import WrapperCounter from './WrapperCounter';
function CounterFn({count,incrementCounter}){
return(
<button onClick={incrementCounter}>Counter inside functiona component {count}</button>
)
}
export default WrapperCounter(CounterFn)

How to handle multiple context within React?

New to React - I am trying to use multiple contexts within my App component, I tried following the official guide on multiple contexts.
Here is my current code:
App.js
import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import AuthContext from "./AuthContext";
import LayoutContext from "./LayoutContext";
import LoadingScreen from "./LoadingScreen";
class App extends React.Component {
render() {
const { auth, layout } = this.props;
return (
<LayoutContext.Provider value={layout}>
<LoadingScreen />
<AuthContext.Provider value={auth}>
<AuthContext.Consumer>
{auth => (auth.logged_in ? console.log("logged in") : <Login />)}
</AuthContext.Consumer>
</AuthContext.Provider>
</LayoutContext.Provider>
);
}
}
render(<App />, document.getElementById("root"));
Login.js
import React from "react";
class Login extends React.Component {
render() {
return (
<div></div>
);
}
}
export default Login;
AuthContext.js
import React from "react";
const AuthContext = React.createContext({
logged_in: false
});
export default AuthContext;
LayoutContext.js
import React from "react";
const LayoutContext = React.createContext({
show_loading: false
});
export default LayoutContext;
LoadingScreen.js
import React from "react";
import LayoutContext from "./LayoutContext";
class LoadingScreen extends React.Component {
render() {
return (
<LayoutContext.Consumer>
{layout =>
layout.show_loading ? (
<div id="loading">
<div id="loading-center">
<div className="sk-chasing-dots">
<div className="sk-child sk-dot1"></div>
<div className="sk-child sk-dot2"></div>
</div>
</div>
</div>
) : null
}
</LayoutContext.Consumer>
);
}
}
export default LoadingScreen;
Following the example, I never really understood how this.props (in App.js) could hold my different contexts.
Both auth and layout show up as undefined, this.props is empty, which will in turn cause my app to throw errors such as Cannot read property 'show_loading' of undefined
I immediately liked the example provided in the React documentation, but I can't get this to work.
I've made a small snippet to show you how you could structure your context providers and consumers.
My App component in this case is the root of the app. It has all the providers, along with the value for each one of them. I am not changing this value, but I could if I wanted to.
This then has a single child component, MyOutsideComponent, containing all the chained consumers. There are better ways to do this, I just wanted to show you, one by one, how chaining consumers work. In practice you can neatly reduce this using a few techniques.
This MyOutsideComponent has the actual component, MyComponent, which takes all the context elements and just puts their value on the page. Nothing fancy, the point was to show how the values get passed.
let FirstContext = React.createContext('first');
let SecondContext = React.createContext('second');
let ThirdContext = React.createContext('third');
let FourthContext = React.createContext('fourth');
let MyComponent = (props) => {
return (<span >{Object.values(props).join(" ")}</span>);
};
let App = (props) => {
return (
<FirstContext.Provider value="this is">
<SecondContext.Provider value="how you">
<ThirdContext.Provider value="pass context">
<FourthContext.Provider value="around">
<MyOutsideComponent />
</FourthContext.Provider>
</ThirdContext.Provider>
</SecondContext.Provider>
</FirstContext.Provider>
);
};
let MyOutsideComponent = () => {
return ( < FirstContext.Consumer >
{first =>
(< SecondContext.Consumer >
{second =>
(< ThirdContext.Consumer >
{third =>
(<FourthContext.Consumer >
{fourth =>
(<MyComponent first={first} second={second} third={third} fourth={fourth} />)
}
</FourthContext.Consumer>)
}
</ThirdContext.Consumer>)
}
</SecondContext.Consumer>)
}
</FirstContext.Consumer>);
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Now, for the actual explanation. createContext gives you two actual components: a Provider and Consumer. This Provider, as you found out, has the value. The Consumer takes as child a single function taking one argument, which is your context's value.
This is where the docs are a bit unclear, and a bit which I hope I can help a bit. This does not get passed automatically in props unless the Provider is the direct parent of the component. You have to do it yourself. So, in the example above, I chained four consumers and then lined them all up in the props of my component.
You've asked about class-based components, this is how it ends up looking like:
let FirstContext = React.createContext('first');
let SecondContext = React.createContext('second');
let ThirdContext = React.createContext('third');
let FourthContext = React.createContext('fourth');
class MyComponent extends React.Component {
render() {
return ( < span > {Object.values(this.props).join(" ")} < /span>);
}
}
class App extends React.Component {
render() {
return (
<FirstContext.Provider value = "this is" >
<SecondContext.Provider value = "how you" >
<ThirdContext.Provider value = "pass context" >
<FourthContext.Provider value = "around" >
<MyOutsideComponent / >
</FourthContext.Provider>
</ThirdContext.Provider >
</SecondContext.Provider>
</FirstContext.Provider >
);
}
}
class MyOutsideComponent extends React.Component {
render() {
return (
<FirstContext.Consumer >
{ first =>
(< SecondContext.Consumer >
{ second =>
( < ThirdContext.Consumer >
{ third =>
( < FourthContext.Consumer >
{ fourth =>
( < MyComponent first = {first} second={second} third={third} fourth={fourth} />)
}
</FourthContext.Consumer>)
}
</ThirdContext.Consumer>)
}
</SecondContext.Consumer>)
}
</FirstContext.Consumer>
);
}
}
ReactDOM.render( < App / > , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app" />

Categories