In the code snip below, execution never reaches to useNavigate() line. It terminates at useContext() line without any error message. However, I managed to use useContext at another place without any issue. That makes me to think problem is related with, where and how I call logOut and relatedly useContext.
import AuthContext from '../store/auth-context';
import { useState, useRef, useContext } from 'react';
export default function LogOut() {
const authCtx = useContext(AuthContext);
const navigator = useNavigate();
authCtx.logout();
// optional: redirect the user
navigator('/dbsection');
return;
};
The place where LogOut is called:
import logOut from '../components/logOut.js';
<NavBtn>
<NavBtnLink to='/formLogIn'>Log In</NavBtnLink>
<NavBtnLink to='/dbsection' onClick={logOut}>Log Out</NavBtnLink>
</NavBtn>
</Nav>
I tried to create an instance from useContext() hook. I wanted to call a function of related context but I couldn't create the instance.
The reason of the problem is that useContext hook is called/triggered via onClick handle. I dont know why but for some reason, React doesnt allow this. I just moved content of external 'logOut' function into the component where I call logOut, and useContext worked as well.
Why React doesnt allow useContext hook, or maybe all hooks to be called through onClick handle, thats still a question for me.
Related
In my project I have the index.tsx calling the App.tsx that uses a UserProvider and AuthProvider. I received an invalid call error from inside the UserProvider because I'm using the useState hook.
This problem occurs also if I create a custom hook, I can't use any hook inside the custom hook.
This is my index.tsx:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
//import './commons/global.css';
import reportWebVitals from './reportWebVitals';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
reportWebVitals();
This is my App.tsx:
import { useEffect, useState } from 'react';
import { BrowserRouter, useNavigate } from 'react-router-dom';
import {
AuthService,
AuthProvider,
useAuth,
useLogin,
UserProvider,
} from 'reactjs-oauth2-pkce-provider';
import './index.css';
import Routes from './routes';
const authService = new AuthService({...});
const App = () => {
const [user, setUser] = useState({});
const [loading, setLoading] = useState(true);
// for every refresh of the page, check if there is a user in localStorage
useEffect(() => {
const user = localStorage.getItem('user');
if (user) {
setUser(JSON.parse(user));
}
setLoading(false);
}, []);
return (
<UserProvider>
<AuthProvider authService={authService}>
<Routes />
</AuthProvider>
</UserProvider>
);
};
export default App;
This is my UserProvider.tsx:
import React, { ReactElement, useState } from 'react';
import { UserContext } from '#app/application/UserContext';
export const UserProvider = ({ children }: { children: ReactElement }) => {
const [user, setUser] = useState({});
console.log(user);
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
};
There is no function that is calling the hook outside a functional component (there is?)!
A important thing to note is that the UserProvider.tsx is part of a separate package for authentication that I'm building and importing from it with yarn link.
I already tested to install directly from github without success.
I already tested declaring the function with React.FC type but the result is the same.
The understanding that I have from it until now is that the react do not know that the App() function is a functional component and the call for UserProvider is inside a functional component.
I'm expecting that I can use hooks inside the provider, to work useState, useEffect, useNavigate.
The error message is telling you that your error is in fact originating from your Hook call in UserProvider.tsx at line 5.
When you don't import components traditionally as react Components such as
<Component/>
and instead import them as a function such as
return component();
or as in your case, importing them as a wrapper:
<Component>Parent</Component>
Then React hooks won't work.
I would recommend using Redux for logins or the useContext Hook to manage logins if you can't figure out the Traditional React Hooks way of managing this. useContext is also a React hook which would cause the same error if implemented in a similar way, but Redux wouldn't cause you to adhere to any of these strict React rules..
There's a lot of existing Login Templates on Github, including ones with Redux. Implementing Logins is the most boring and tedious process I've dealt with, which can usually take extremely long. Traditionally I use App Skeletons with login capabilities already implemented, and then add all the fun code over, but try the suggestions I mentioned.
The error message that you posted contains three possible reasons for the error. Based on the information that you've provided, reason #3 seems like the most likely culprit.
You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app.
I don't see anywhere in your code, at least not in what you've posted, that you are violating the rules of hooks.
It's what you've said here that jumps out:
A important thing to note is that the UserProvider.tsx is part of a separate package for authentication that I'm building and importing from it with yarn link.
I suspect that your reactjs-oauth2-pkce-provider package is declaring react in the dependencies rather than the peerDependencies. This would cause you to have two copies of react -- one from the package and another from your main app. If these two versions don't match, you could be dealing with reason #1 as well.
The "Duplicate React" section of the docs contains a few checks that you can do to confirm that you do in fact have two copies of React.
If you see more than one React, you’ll need to figure out why this happens and fix your dependency tree. For example, maybe a library you’re using incorrectly specifies react as a dependency (rather than a peer dependency).
Since this is a package that you created and control, you can fix the problem at its root. the solution is to remove react from the dependencies array in your package's package.json and move it to the peerDependencies array instead. You may also need it in the devDependencies. Here is a good example.
i am trying to implement the history.push prototype inside useEffect hook . this is how I did it :
useEffect(()=>
{
reset()
props.history.push('/')
},[signUpSuccess])
I have tried to import useHistory , yet its no longer supported
As you said, useHistory is no longer supported. It has been replace by useNavigate in react-router version 6. You can use it like this:
const history= useNavigate()
history('/')
instead of:
const history = useHistory()
history.push('/')
EDIT CONCERNING THE AUTOMATIC REDIRECT ON CLICK
The React documentation states:
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
This means that the code inside the useEffect hook will be executed each time the component will be rendered/updated.
Code Sandbox link:
and trying to follow this article
On successful login(/auth/login), the user should be routed to the dashboard(/admin/summary). If the login is successful, I am also storing an access token.
I have a PrivateRoute component for this. The problem is that on successful login, the URL is getting updated but the component is not getting rendered.
PS: about the dashboard, this is a single page application so, the dashboard has topbar, sidebar, and the right content and altogether these things are coupled inside <AdminLayout/>. So, in my AppRouter, I have to render the <AdminLayout/> and just any one component.
All the react and redux code is included in the code sandbox.
Since in your code you create your own history object (it happens in you history.js file, when you call createBrowserHistory()) but doesn't pass it to your Router, nothing happens.
There are 2 possible solutions:
1. Don't create a history object yourself, but use useHistory hook inside your component
Working Demo
With this approach, you should remove history.push from login.actions.js (which imports history) and use history.push in Login.js (which uses useHistory hook):
// login.actions.js
...
loginService.login(userid, password, rememberPassword).then(
(userid) => {
dispatch(success(userid, password, rememberPassword));
// history.push(from); <-- commented out!
},
(error) => { ... }
);
};
...
// Login.js
function handleSubmit(e) {
...
const { from } = {
from: { pathname: "/admin/summary" }
};
history.push(from) // <-- added!
dispatch(loginActions.login(inputs, from));
...
}
useHistory exposes the history object of BrowserRouter (I think this is implied in this official blog post).
2. Create a history object yourself, but pass it to a Router component
Working Demo
This approach would require you to make several changes:
Creating the history object on your own means you become responsible to provide it to a router component, but it can't be a BrowserRouter, but the base Router component (see these Github answers: 1, 2).
Once you import Router (instead of BrowserRouter), you need to get rid of any useLocation and useHistory imports, otherwise you'll get errors.
I also had to unify the history object export and imports, so that it is exported as the default export (i.e., export default history), and it is imported as the default import (i.e., import history from "./history"; instead of import { history } from "./history")
(P.S: this approach can be seen implemented elsewhere on SO, for example here or here (the latter explicitly installs history, but it's not needed in your case).
Have a ReactJS + Redux + Saga application that was recently updated to use the latest (or close to latest) versions of the respective JS libraries. After the library updates (no code changes) and running the application, I immediately see the "Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state." warning message in the console. It looks to be triggered by redux when I invoke the dispatch function (which then calls a function in Provider.js, then goes through react-dom, and then in turn writes the warning message. Again nothing in my code has changed, and my code is essentially built using stateless functions.
Not sure how to go about figuring out what is causing this warning-- although the app still runs ok as expected. Using React 16.8.6, react-redux 6.0.1, react-router-dom 5.0.0, redux 4.0.1, redux-saga 1.0.2, and connected-react-router 6.4.0.
Below is a sample page that would cause the warning message:
import React from 'react'
import {connect} from 'react-redux'
import {links} from '../links'
import {notify} from '../notifications'
const Home = props => {
const {dispatch} = props
return (
<main>
<p>
Go to Details...
</p>
</main>
)}
const dispatcher = dispatch => {
dispatch(notify(links.HOME))
return {dispatch}
}
export default connect(null, dispatcher)(Home)
You cannot call to dispatch inside the disaptcher function.
react-redux's connect parameters are:
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
mapDispatchToProps is what you called dispatch. These params are eventually run as functions that called in the render loop of the connected component. When you dispatch in the render loop it changes the state of a React component (looks like it's the Provider), which is forbidden by React.
Solution
Move the dispatch(notify(links.HOME)) to lifecycle method. For example you can add to the Home component (this will require to rewrite the Home component as an extension of React.Component class:
componentDidMount() {
dispatch(notify(links.HOME))
}
UPDATE
If you want to do this with classless component see that question
I have a functional Component which is using the hook useCallback. For the last few days everything was just fine. All worked as it should. Today I start up the app and I have this error:
React Hook "useCallback" is called in function "loginPage" which is neither a React function component or a custom React Hook function
This makes no sense because it has been fine. For debugging I simply erased all code on the page except that one coed and even just put a useCallback template in its place, but still the same. It is as if it has been removed from react entirely.
I checked my react version and find 16.8.6 also in react-dom.
Does anyone have any ideas?
import React, {Fragment,useCallback } from 'react';
import { Redirect} from 'react-router-dom';
import {useDropzone} from 'react-dropzone';
const loginPage = (props) => {
const callbackFunction = useCallback(() => {
console.log("callback called");
// Do something with callbackCount ...
return true;
}, []);
}
I see three problems why the error occurred.
which is neither a React function component or a custom React Hook function
loginPage is not a component. useCallback is a hook and it needs to be called inside a function component (not a class component) or in another hook (a function whose name starts with "use"). Check out the rules of hooks.
And also the component name should start with a capital letter, so it should be LoginPage for it to be a valid React component.
You are not returning anything from your component.