So in my app I have a login-component and an authenticator-component. The last one works with QR code authorization etc.
Since the package "node-sass" is deprecated now, I changed to the "sass" NPM package. I had to upgrade "react-router" and "react-router-dom" as well to their latest version (6...).
Here's my dependencies:
"dependencies": {
"#material-ui/core": "^4.11.0",
"#material-ui/icons": "^4.9.1",
"#material-ui/lab": "^4.0.0-alpha.56",
"#react-pdf/renderer": "^1.6.12",
"#reduxjs/toolkit": "^1.4.0",
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"axios": "^0.20.0",
"caniuse-lite": "^1.0.30001197",
"moment": "^2.29.1",
"qrcode.react": "^1.0.0",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-async": "^10.0.1",
"react-dom": "^16.13.1",
"react-fade-in": "^1.1.0",
"react-icons": "^3.11.0",
"react-movable": "^2.5.3",
"react-outside-click-handler": "^1.3.0",
"react-qr-reader": "^2.2.1",
"react-redux": "^7.2.1",
"react-router": "^6.0.2",
"react-router-dom": "^6.0.2",
"react-scripts": "3.4.3",
"redux": "^4.0.5",
"redux-axios-middleware": "^4.0.1",
"redux-devtools-extension": "^2.13.8",
"redux-thunk": "^2.3.0",
"sass": "^1.43.4",
"xlsx": "^0.16.8"
},
So my next step was to change everything from "react-router" and "react-router-dom" to use their latest items, like "useHistory" was changed to "useNavigate" etc.
Their "history.push("/route")" was also changed to "navigate("/route")" now, so I changed those as well.
And lastly, they removed the "withRouter" function from their package, which used to be required for navigation to work inside main App. It used to be like this:
export default withRouter(App);
But now this is the hook that it replaces:
import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
export const withRouter = (Component) => {
const Wrapper = (props) => {
const navigate = useNavigate();
const location = useLocation();
return (
<Component
{...props}
navigate={navigate}
location={location}
/>
);
};
return Wrapper;
};
And then you import that one, and use "withRouter(App)" etc...
Here's (part of) my App Routing:
return (
<ThemeProvider theme={theme}>
<Loading />
<Header
menuHandler={() => {
changeMenu(!showMenu);
}}
setActive={setActive}
/>
<main className="main">
<MenuBar
showMenu={showMenu}
toggleMenu={() => changeMenu(!showMenu)}
active={active}
setActive={setActive}
/>
<Container className="main__container" id="main__container">
<MySnackbar />
<Modal />
<Routes>
<Route
path="/scanner"
element={
<ScannerScreen />
}
/>
<Route
path="/authenticator"
element={
<Authenticator />
}
/>
<Route
path="/login"
element={
<Login />
}
/>
...
As you can see, where it says now "Routes" is where it used to say "Switch" in previous "react-router-dom" versions.
I used to navigate between pages, like so:
import { useNavigate } from "react-router-dom";
...
const navigate = useNavigate();
...
navigate("/authenticator", {
authMode: "login",
username: user.username,
});
As you can see, I'm using the V6 "navigate" from "react-router-dom" now instead of the previous "history.push('/authenticator')" for example.
This navigation works, however no props are passed (like authMode & username) and the props are always "undefined" in the target/new component, when here/source component they are filled in.
No matter what I do, props are always undefined, like so:
// both authMode & username will be undefined
const Authenticator = ({ authMode, username }) => {...}
// props will be undefined
const Authenticator = (props) => {...}
// both of these will return undefined values
const Authenticator = () => {
const { authMode, username } = useParams();
const { authMode, username } = useLocation();
}
Does anyone have any idea how I can properly pass props from Login to my Authenticator, using Javascript, like so:
navigate("/authenticator", {
authMode: "login",
username: user.username,
});
Thanks!
So, of course, right after posting a stackoverflow post I kept on digging and finally found "a" solution myself. I'm not sure if this is the best way, but here it is.
Looking at this post: https://stackoverflow.com/a/64566486/3384458 , props are no longer "just" passed to other components. It has to go via the "location" prop now.
So now I have to do it like this, in my Login-component:
navigate("/authenticator", {
state: {
authMode: "login",
username: user.username,
}
});
You have to set the "location.state" prop of "location", like above.
Now the "location.state" prop will contain my object with "authMode" and "userName".
In my Authenticator-component, I do it like this now:
const { authMode, username } = useLocation().state;
Here's another helpful link for react-router v6: https://remix.run/blog/react-router-v6
Related
I am using octa-react library for authentication here. I have also given the dependencies below. I'm trying to pass my config data to octa login page if its authenticated then redirect to admin page in the project. In terminal its not showing any error but when I run this code its showing me this error. I'm stuck with this from last three days.
No routes matched location "/"
App.js
import React,{ PureComponent } from "react";
import axios from "axios";
import { BrowserRouter as Router, Route, Routes, useNavigate } from "react-router-dom";
import { OktaAuth, toRelativeUrl } from '#okta/okta-auth-js';
import { Security, LoginCallback, SecureRoute } from "#okta/okta-react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { createBrowserHistory } from "history";
import Home from "./Home";
import { allReducers } from "./redux/reducers";
import Loader from "./views/Common/Loader";
const browserHistory = createBrowserHistory();
const oktaauth = new OktaAuth(config.oidc);
const store = createStore(
allReducers,
{},
window.devToolsExtension && window.devToolsExtension()
);
const HasAccessToRouter = ({ data }) => {
const history = useNavigate();
const restoreoriginalUri = async (_oktaAuth, originalUri) => {
history.replace(toRelativeUrl(originalUri || '/', window.location.origin));
};
return (
<Security {...data.oidc} oktaAuth={oktaauth} restoreOriginalUri={restoreoriginalUri} >
<SecureRoute path="/" exact element={ <Home data={data} />}/>
<Routes>
<Route exact path="/implicit/callback" element={LoginCallback} />
</Routes>
</Security>
);
};
class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
isLoading: true,
response: {},
};
}
componentDidMount() {
this.getSettingsFromFile();
}
getSettingsFromFile = async () => {
try {
const response = await axios.get(
`${
process.env.PUBLIC_URL
? process.env.PUBLIC_URL
: `${window.location.origin}`
}/settings.json`
);
localStorage.setItem("apiUrl", response.data.API_URL || "");
this.setState({
isLoading: false,
response: response.data,
//dashboardtype:""
});
} catch (error) {
this.setState({
isLoading: false,
response: {},
});
}
};
render() {
const { response, isLoading } = this.state;
if (isLoading) {
return <Loader />;
}
return (
<div>
<Provider store={store}>
<Router
history={browserHistory}
basename={process.env.PUBLIC_URL || "/admini"}>
<Routes>
<Route element={ <HasAccessToRouter data={response} /> } />
</Routes>
</Router>
</Provider>
</div>
);
}
}
export default App;
Home.js
import { useOktaAuth } from "#okta/okta-react";
import React, { useEffect, useState } from "react";
import DefaultLayout from "./containers/DefaultLayout/DefaultLayout";
// import Login from "./Login";
import { Spin, Button } from "antd";
import { isEmpty } from "lodash";
const Home = (props) => {
const { authState, oktaAuth } = useOktaAuth();
const [userInfo, setUserInfo] = useState(null);
useEffect(() => {
if (!authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setUserInfo(null);
} else {
oktaAuth.getUser().then((info) => {
setUserInfo(info);
});
}
}, [authState, oktaAuth ]); // Update if authState changes
// redirect to okta login
const login = async () => {
oktaAuth.signInWithRedirect();
};
return (
<div>
{authState.isAuthenticated !== null && (
<div>
{authState.isAuthenticated && !isEmpty(userInfo) ? (
<div>
<DefaultLayout {...props} />
</div>
) : (
<div className="spinner">
<Spin tip="Loading..." />
</div>
)}
{!authState.isAuthenticated && (
<div>
<p>Please login to access the portal.</p>
<Button id="login-button" type={"primary"} onClick={login}>
Login
</Button>
</div>
)}
</div>
)}
</div>
);
};
export default Home;
package.json
"dependencies": {
"#ant-design/icons": "^4.7.0",
"#coreui/coreui": "^4.2.0",
"#coreui/coreui-plugin-chartjs-custom-tooltips": "^1.3.1",
"#coreui/icons": "2.1.0",
"#coreui/react": "^4.3.0",
"#okta/okta-auth-js": "^6.7.6",
"#okta/okta-react": "^6.5.0",
"#okta/okta-signin-widget": "^6.5.0",
"antd": "^4.21.7",
"antd-password-input-strength": "^2.0.1",
"axios": "^0.27.2",
"bootstrap": "^5.2.0",
"classnames": "^2.3.1",
"core-js": "^3.23.5",
"cross-env": "7.0.3",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"flag-icon-css": "^3.3.0",
"font-awesome": "^4.7.0",
"history": "^5.3.0",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"moment-timezone": "^0.5.34",
"node-sass": "^7.0.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-app-polyfill": "^3.0.0",
"react-chartjs-2": "^4.3.1",
"react-datalist": "^4.0.0",
"react-datalist-field": "^20.3.1",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-hot-loader": "^4.13.0",
"react-idle-timer": "^5.4.1",
"react-loadable": "^5.5.0",
"react-redux": "^8.0.2",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-spinners": "^0.13.3",
"react-test-renderer": "^18.2.0",
"reactstrap": "^9.1.2",
"redux": "^4.2.0",
"redux-thunk": "^2.4.1",
"simple-line-icons": "^2.5.5"
}
This question already has answers here:
React navigate router v6 invalid hook call
(5 answers)
Problem in redirecting programmatically to a route in react router v6
(1 answer)
Closed 11 months ago.
How to navigate through routing on button click in react.
I am trying to acess some other class using routing ( "react-router": "^6.2.1",) in reactJS. When I am clicking I am getting this error.
Cannot read properties of undefined (reading 'push')
Here is my class
import React, { Component } from "react";
import { withRouter } from 'react-router-dom';
import { useHistory } from "react-router-dom";
import Button from "#mui/material/Button";
class MyBar extends Component {
constructor(props) {
super(props);
this.state = {};
this.createNew = this.createNew.bind(this);
}
createNew () {
this.props.history.push('/new');
}
render() {
return (
<div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="d-grid gap-2 col-2 mx-auto">
<button type="create" class="btn btn-outline-primary" onClick={this.createNew}> Create Post </button>
</div>
</div>
</nav>
</div>
);
}
}
export default MyBar;
Here is my dependency
"dependencies": {
"#emotion/react": "^11.8.1",
"#emotion/styled": "^11.8.1",
"#mui/material": "^5.4.3",
"#testing-library/jest-dom": "^5.16.2",
"#testing-library/react": "^12.1.3",
"#testing-library/user-event": "^13.5.0",
"axios": "^0.26.0",
"bootstrap": "^5.1.3",
"draft-js": "^0.11.7",
"font-awesome": "^4.7.0",
"react": "^17.0.2",
"react-bootstrap": "^2.1.2",
"react-dom": "^17.0.2",
"react-draft-wysiwyg": "^1.14.7",
"react-icons": "^4.3.1",
"react-pro-sidebar": "^0.7.1",
"react-router": "^6.2.1",
"react-router-dom": "^6.2.1",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.4"
},
But in other version( "react-router-dom": "^5.2.0",) of app by using this in the export
export default withRouter(ListOfEmployee);
I was easily able to navigate.
Can anybody help me here.
PS: I know there are multiple answer but none of them are its working and not getting much from the git and offcial docs.
In v6 you can use useNavigate:
const navigate = useNavigate()
navigate('/new')
It should work
class Login extends Component {
nextPath(path) {
this.props.history.push(path);
}
render() {
return (
<div>
<button type='button' onClick={() => this.nextPath('/yourpath') } >Button</button>
</div>
);
}
import { useState } from 'react';
import "./Searchbar.css"
import SearchIcon from '#material-ui/icons/Search';
import MicIcon from '#material-ui/icons/Mic';
import { Button } from '#material-ui/core';
import { useHistory } from "react-router-dom";
function Searchbar() {
const history = useHistory();
const[input, setInput] = useState('');
const search = (e) =>{
e.preventDefault();
// when the click enter button
history.push("/search")
}
return (
<form className="search">
<div className="search_box">
<SearchIcon className="search_icon" />
<input value={input} onChange={e => setInput(e.target.value)}></input>
<MicIcon />
</div>
<div className="search_cards">
<Button type='submit' onClick={search} variant="outlined">Google Search</Button>
<Button variant="outlined">I'm Feeling Lucky</Button>
</div>
</form>
)
}
export default Searchbar;
"dependencies": {
"#material-ui/core": "^4.12.3",
"#material-ui/icons": "^4.11.2",
"#testing-library/jest-dom": "^5.14.1",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"
},
this is the my code. i have tried to use **useHistory** hook to redirect to the searchpage when i have clicked that search button.
but after adding Use History hook it displays message like
Invalid hook call. Hooks can only be called inside of the body of a function component.
is it wrong that the way i have called **useHistory** hook???
Github repo
I'm implementing react application. By the way, I'm encountering react router showing blank page without any error or exception. I have searched through stack overflow and knowing that browse history might be missing. I have no luck still even implemented browseHistory and the page is still showing blank.
Here is my code,
import React from 'react';
import ReactDOM from 'react-dom';
//import App from 'components/App.js';
//import Home from 'components/Home.js';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { Router, Route, IndexRoute, browserHistory, hashHistory, RouteHandler } from 'react-router';
injectTapEventPlugin();
var Home = React.createClass({
render: function() {
return (<h1>Welcome to the Home Page</h1>);
}
});
let App = React.createClass({
render() {
<div className="nav">
<h1>It's work</h1>
<RouteHandler/>
</div>
}
});
let routes = (
<Route name="app" path="/" handler={App} >
<Route name="home" path="/home" handler={Home} />
</Route>
);
ReactDOM.render(<Router routes={routes} history={browserHistory} />, document.getElementById('app'));
Appreciate to somebody's contribution if you have idea about this.
Here is my package json.
{
"name": "finalize",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node server.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.24.0",
"babel-eslint": "^7.2.1",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
"eslint": "^3.18.0",
"eslint-plugin-react": "^6.10.3",
"express": "^4.15.2",
"file-loader": "^0.10.1",
"react-hot-loader": "^1.3.1",
"webpack": "^2.3.2",
"webpack-dev-middleware": "^1.10.1",
"webpack-hot-middleware": "^2.17.1"
},
"dependencies": {
"material-ui": "^0.17.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router": "^3.0.2",
"react-tap-event-plugin": "^2.0.1"
}
}
Issue is you forgot to use return in App component, App is main component, so if you don't return anything it will always show blank page, use this:
let App = React.createClass({
render: function {
return (
<div className="nav">
<h1>It's work</h1>
<RouteHandler/>
</div>
)
}
});
Instead of handler use component, handler has been deprecated and doesn't supported in v3.x. check this: https://github.com/ReactTraining/react-router/issues/2887
Use it like this:
let App = React.createClass({
render: function() {
return (
<div className="nav">
<h1>It's work</h1>
{this.props.children}
</div>
);
}
});
let routes = (
<Route name="app" path="/" component={App} >
<Route name="home" path="/home" component={Home} />
</Route>
);
ReactDOM.render(<Router routes={routes} history={browserHistory} />, document.getElementById('app'));
Check the doc also they are using component: https://github.com/reactjs/react-router-tutorial/tree/master/lessons/02-rendering-a-route
I'm getting this error:
<Provider> does not support changing store on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions.
I have a component with this:
import React, { Component } from 'react';
import {
AppRegistry,
NativeAppEventEmitter
} from 'react-native';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducers from './src/reducers';
import Onboarding from "./src/onboarding/Onboarding";
import Home from "./src/home/Home";
import codePush from 'react-native-code-push';
class Edmund extends Component {
...
startScreen() {
if (this.state.screen === "HOME" ) {
return (<Home />);
}
return (
<Onboarding />
);
}
render() {
return (
<Provider store={ createStore(reducers) }>
{ this.startScreen() }
</Provider>
)
}
AppRegistry.registerComponent('Edmund', () => Edmund)
My src/reducers/index.js file:
import { combineReducers } from 'redux';
export default combineReducers({
libraries: () => []
});
My packages:
{
"name": "Indigo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"lodash": "^4.13.1",
"react": "^15.2.0",
"react-native": "^0.27.1",
"react-native-apple-pay": "0.0.0",
"react-native-code-push": "^1.11.0-beta",
"react-native-loading-spinner-overlay": "^0.3.0",
"react-native-navigation": "^1.0.2",
"react-native-paged-scroll-view": "^2.0.1",
"react-native-progress": "^3.0.1",
"react-redux": "latest",
"redux": "^3.0.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"eslint": "latest",
"eslint-config-airbnb": "latest",
"eslint-plugin-import": "^1.16.0",
"eslint-plugin-jsx-a11y": "latest",
"eslint-plugin-react": "latest"
}
}
I'm not even doing anything fancy so I don't get why there's this error. Can anyone help?
If you dig into the react-redux code a bit you see this
if (store !== nextStore) {
warnAboutReceivingStore()
}
So it would seem all you would have to do is move the createStore call outside.
store = createStore(reducers)
class Edmund extends Component {
...
startScreen() {
if (this.state.screen === "HOME" ) {
return (<Home />);
}
return (
<Onboarding />
);
}
render() {
return (
<Provider store={ store }>
{ this.startScreen() }
</Provider>
)
}
Haven't tested it but should work.
I got the same error and the workaround is to remove the DevTools.
<Provider store={store} >
<App />
</Provider>
In the component App's render() method, there is a:
<DevTools />
After I removed the DevTools, the error disappeared.
This is not a good solution, just for your reference.