useContext giving me undefined value on different components after setting that value - javascript

I am creating a context for a log in, so after creating the context I wrap all my routes with that context.provider and send the initial value to each child, which in my case is a useState:
<userContext.Provider value={{loggedUser, setLoggedUser}}>
I have a component LogInMenu.jsx that basically sets the loggedUser (loggedUser has a username/password structure) to a valid user. I consume the context in LogInMenu.jsx like this:
const { loggedUser, setLoggedUser } = useContext(userContext)
After succesfully console logging the loggedUser value in LogInMenu.jsx (just to make sure it was correct) I go to my other component called Dashboard.jsx and consume the context there the same way as I consumed it in LogInMenu.jsx, but this time, If I console log the loggedUser it gives me undefined value.
Note: I have imported useContext hook in each of the components that use it like this:
import React, { useState, useContext } from 'react';
and the context I created like this:
import { userContext } from './App';
If you need more code to understand the issue I can provide it.

I was going thru the code sandbox example, few points to consider
try moving the code inside the submit event handler
const submitData = async (e) => {
e.preventDefault();
// Ideally use post instead of get
// pass user id and password to Api
// password should never be stored in plain text in backend
// depending on the backend store it as hash and authenticate
// user Id/name and password in the backend
const loginResponse = await axios.get(`http://localhost:8002/users/${user}`)
if (loginResponse.isSuccess) {
setLoggedUser(loginResponse.userInfo)
}
};
You can get a good idea about React with their new documentation.
Cheers

Related

Why isn't this React component updated when dependency changes?

I have this simple React component with a search bar, it gets the input value and navigates to an URL setting the input value as a query param. Once in the component, it gets the 'keyword' from the URL query params and calls an API to get results.
It only works the first time. But if I change the input value it doesn't update the 'keyword' variable value, even though the URL is properly updated.
Why isn't my variable updated?
export default function Resultados () {
let keyword = new URLSearchParams(window.location.search).get('keyword')
const apiKey = '123' ;
useEffect(()=>{
axios
.get(`https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=es-ES&query=${keyword}&page=1&include_adult=false
`)
.then(res=>{
console.log(res.data)
})
},[keyword])
return (
<>
<h2>Resultados de {keyword}</h2>
</>
)
}
I've included the keyword variable on the useEffect dependency array, but it seems the variable is not changing.
The dependency array to a useEffect will never cause your component to render. In fact, it's only useful if the component is already rendering, at which point it can skip the effect if nothing has changed. Instead, if you want the component to render, you must set state (either here or in some parent component).
So you either need to write custom code which detects when the url changes, and at that point set state; or you can use an existing routing library such as react-router or react-location, which have already written that code for you. For example, here's how you would do it in react-router:
import { useSearchParams } from 'react-router';
export default function Resultados () {
const [searchParams] = useSearchParams();
const keyword = searchParams.get('keyword');
// rest of your code is the same
}

React Hooks must be called in the exact same order in every component render error when building app - NextJs/Javascript

I am building a NextJs App and everything works well in dev. However when I am trying to build the application I get the errors:
./pages/genre.js/[genre].js
15:14 Error: React Hook "useFetchTrendingCatagory" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks
17:14 Error: React Hook "useFetchTopRatedCatagory" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks
19:14 Error: React Hook "useFetchMovieGenreResults" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks
My code is below:
import React from "react";
import { useRouter } from "next/router";
import useFetchMovieGenreResults from "../../hooks/useFetchMovieGenreResults";
import { useState } from "react";
import useFetchTrendingCatagory from "../../hooks/useFetchTrendingCatagory";
import useFetchTopRatedCatagory from "../../hooks/useFetchTopRatedCatagory";
const useMovies = (genre) => {
switch (genre) {
case 'Trending':
return useFetchTrendingCatagory()
case 'Top Rated"':
return useFetchTopRatedCatagory()
default:
return useFetchMovieGenreResults(genre)
}
}
export default function Genre () {
const router = useRouter();
const { genre } = router.query;
const mymovies = useMovies(genre)
return (
<div>
{/* <Navbar /> */}
<div>{genre}</div>
<Moviegenreresults movies={mymovies} />
</div>
)
}
Why is this error happening and is there a work-around for this error?
What's happening is exactly what the error says,
useMovies gets a different hook based on a condition which is the name of the genre,
therefor the order of your hooks may be changed according to the arguments you pass to the useMovies hook.
Instead of having a switch that is returning a different hook based on the genre you passed make all the hook logic inside of one f.e useMovies hook and everything that needs to be modified (I assume for example the endpoint or the data you pass to that endpoint) pass it as your argument and make it work there.
Technically the error is exactly how it sounds. You can't call hooks conditionally. What you're doing in the intermediate useMovies function with the switch statement is conditionally calling a hook. You may want to make that hook just something like useFetchMovies and just pass the genre into it, then inside of the hook itself do the logic that is happening in the useMovies function. Assuming you are just fetching from different endpoints in the different hooks you could do something like this, then return the fetcher function, or even use it in an effect if you really wanted to.
const useFetchMovies = (genre = null) => {
const [movies, setMovies] = useState([]);
const fetchMovies = async() => {
let url;
switch (genre) {
case "Trending":
url = "whatever the url you need is for this";
case 'Top Rated"':
url = "whatever the url you need is for this";
default:
url = "whatever the url you need is for this";
}
try {
const response = await fetch(url);
console.log('response', response)
setMovies(response);
} catch (err) {
console.error(err);
throw err;
}
};
return {
movies,
setMovies,
fetchMovies
};
};

Am I unable to use inline "if" with useEffect in a functional React component?

I am currently trying to work with Okta's React SDK to build an application using React using TypeScript, and I've chosen to use functional components instead of class-based ones.
As such, I am having an issue with rendering part of my app's menu based on the authenticated state of the user. The documentation shows using useEffect() to get the authenticated status of the user then using useState() to store user information based on that status.
That seems quite logical in practice and a great idea, but when I try to use the following component:
import React, { useState, useEffect } from 'react';
import { Dropdown } from 'semantic-ui-react';
import { useOktaAuth } from '#okta/okta-react';
export const HeaderUserMenu = () => {
// Okta Hook, State
const { authState, oktaAuth } = useOktaAuth();
const [ userInfo, setUserInfo ] = useState(null);
// Get info when our state/etc update with this.
useEffect(() => {
if (!authState.isAuthenticated) {
setUserInfo(null);
} else {
oktaAuth.token.getUserInfo()
.then((info: any) => setUserInfo(info))
}
}, [authState, oktaAuth])
return (
{ userInfo &&
<Dropdown.Menu item text={userInfo.username}>
<Dropdown.Item>Log Info</Dropdown.Item>
</Dropdown.Menu>
}
)
}
I receive two errors:
',' expected. - This is pointing to the use of the && operator to check userInfo (is it null or not?) for conditional rendering of this component.
Object is possibly 'null'. - This is pointing to the use of userInfo.username inside the conditionally rendered stuff. The whole point of the logic is to only render if userInfo isn't null, so at this point userInfo can't be null, right?
I'm not sure what I'm doing wrong here.
I get the feeling that it has something to do with useEffect, but I guess I could be wrong, I'm still sort of getting used to using hooks in React, and even though I've used useState before, I've never used effects until now.
Thanks in advance!
',' expected. - This is pointing to the use of the && operator to check userInfo (is it null or not?) for conditional rendering of this component.
The pattern:
{ userInfo &&
The position of the { in your code means "Start of object literal" and not "Insert value into JSX" because you haven't initialised the JSX with a <.
Don't wrap that expression in {}
Object is possibly 'null'. - This is pointing to the use of userInfo.username inside the conditionally rendered stuff. The whole point of the logic is to only render if userInfo isn't null, so at this point userInfo can't be null, right?
You're testing if userInfo.username has a true value.
The error is because userInfo itself might be null.
Trying to access (null).username will throw an exception.
Test if userInfo has a value before testing if it has a username property.
I was able to get around this issue by declaring an interface for the userInfo that would be store in component state.
I also have to check for !authState at the beginning of useEffect.
After doing this, I replaced null with an empty object, and now I'm just checking if the object is empty or not via Object.keys(userInfo).length).
It seems to be working fine and there are no errors being reported.

Invalid hook call React while fetching data from an API

passing country full name at onClick event.
here is error
import React,{useState,useEffect} from 'react'; //
import axios from 'axios';
export const Country = (name) => {
const [country, setCountry] = useState([]);
const requestCountry = (name) => {
axios(`https://restcountries.eu/rest/v2/name/${name}?fullText=true`)
.then((res) =>
// Success handling
setCountry(res.data))
.catch((error) => {
// Error handling
console.error(error.message);
});
}
requestCountry(name)
}
Here is Source of Code Click here to see code
Hooks can be only used inside a Functional Component and not a normal function.
Seems like you are trying to call a Functional Component like normal function with an argument like below.
onClick={() => Country(data.name)}
Instead what you might want to do is, show a list of buttons with country names and then when one of the button is clicked, call a handler function which is the axios API call and then show the response country details or do whatever that you want with those detail data.
To do that, you need to save those responded country detail into a React state.
If country detail exists, show the details. If not, show the list.
So, I forked your codesandbox and edit it like this.
https://codesandbox.io/s/country-data-i479e?file=/src/App.js
Well from the error I can see that you have put the Country call inside a event handler onClick.
The truth is that hooks can not be called inside event listeners. If you need to change the state inside a listener you can do that but you will need to call useState outside of a listener and then call setState wherever you need.
That is because React uses order in which you call hooks to remember how execute your component in subsequent calls.
const [state, setState] = useState();
const onClick = () => {
setState(...);
} ;
As the previous answers have mentioned, you can use hooks only at functional level and not inside a handler.
You just need to move your hook a level up and pass it to your function.
Also, as you're not returning anything from the Country function, there's no need to import "React".
I have modified the code: https://codesandbox.io/s/quiet-night-7cdvi
Check console (Added a useEffect in Country.js just for logging, you can remove it).
Some changed done in your code. Here is the link to view code. https://codesandbox.io/s/practical-dust-lk0x7?file=/src/country.js

Alternative to getState for recurring variables in Redux

I use getState to get a clientId that I need to include in every api call right now. Problem is that this interrupts data flow as the app doesn't rerender when clientId changes. Do I have to manually get the clientId in every component that I need to include it in or is there a better alternative? (clientId is also in store and is fetched first when the user logs in)
Sounds like a good candidate for the use of Context.
Here's a fictitious example of how you can set the client ID at a high level but reference it in nested components without having to query the Redux store each time using Hooks:
App
const ClientContext = React.createContext(null);
function App(props) {
return (
<ClientContext.Provider value={props.clientId}>
<MyApiComponent />
</ClientContext>
)
}
const mapStateToProps = getState => ({
clientId: getState().clientId
})
export default connect(mapStateToProps, {})(App);
So we only need to connect the App to the store to retrieve the client ID, then using Context we can make this value accessible to nested components. We can make use of useContext to pull that value in to each component
function MyApiComponent() {
const clientId = useContext(ClientContext);
...
return <MyNestedApiComponent />;
}
function MyNestedApiComponent() {
const clientId = useContext(ClientContext);
...
}
Whether it's function or class components you are using, the principle is the same - Context is used to share global state down to nested components.

Categories

Resources