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"
}
Related
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
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 have a react native app, this error start to show up after I detached from expo to pure react native, I am a beginner I don't have much experience with react-native.
I tried removing node_modules and installing the dependencies with npm install.
I have included package.json and App.js
App screenshot
package.json
{
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"test": "node ./node_modules/jest/bin/jest.js --watchAll"
},
"jest": {
"preset": "react-native"
},
"dependencies": {
"#babel/runtime": "^7.4.3",
"#expo/samples": "2.1.1",
"date-and-time": "^0.6.3",
"expo-core": "^3.0.1",
"expo-file-system": "^4.0.0",
"expo-font-interface": "^3.0.0",
"expo-image-loader-interface": "^3.0.0",
"expo-permissions-interface": "^3.0.0",
"expo-react-native-adapter": "^3.0.1",
"firebase": "^5.7.2",
"native-base": "^2.10.0",
"react": "16.5.0",
"react-native": "0.55.4",
"react-native-animatable": "^1.3.1",
"react-native-button": "^2.3.0",
"react-native-datepicker": "^1.7.2",
"react-native-dropdownalert": "^3.10.0",
"react-native-elements": "^0.19.1",
"react-native-firebase": "^5.2.3",
"react-native-parallax-scroll-view": "^0.21.3",
"react-native-ratings": "^6.3.0",
"react-native-splash-screen": "^3.2.0",
"react-native-status-bar-height": "^2.2.0",
"react-native-unimodules": "^0.2.0",
"react-native-vector-icons": "^6.4.2",
"react-navigation": "^2.18.2",
"scheduler": "^0.13.6"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"jest": "^24.7.1"
},
"private": true
}
App.js
import React from "react";
import { Platform, StatusBar, StyleSheet, View, Text } from "react-native";
import { Icon } from "react-native-elements";
import AppNavigator from "./navigation/AppNavigator";
import MainTabNavigator from "./navigation/MainTabNavigator";
import Firebase from "./Firebase";
import SplashScreen from 'react-native-splash-screen'
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoadingComplete: false,
isUserLogged: false,
isAuthenticationReady: false
};
Firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
}
componentDidMount() {
SplashScreen.hide();
}
componentWillUnmount() {
this.onTokenRefreshListener();
this.notificationDisplayedListener();
this.notificationListener();
}
onAuthStateChanged = user => {
this.setState({ isAuthenticationReady: true });
this.setState({ isUserLogged: !!user });
};
render() {
if (
!this.state.isLoadingComplete &&
!this.props.skipLoadingScreen &&
!this.state.isAuthenticationReady
) { return <Text />
/*return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
autoHideSplash={true}
/>
);*/
} else {
// As soon as app finishs loading and splash screen hides
// Check if user loggedIn
// Firebase.auth().onAuthStateChanged(user => {
// if (user) {
// this.setState({ isUserLogged: true });
// console.log(user.providerData[0].phoneNumber);
// } else {
// console.log("No user logged in yet!");
// }
// });
return (
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
{this.state.isUserLogged ? <MainTabNavigator /> : <AppNavigator />}
</View>
);
}
}
_loadResourcesAsync = async () => {
return Promise.all([
Asset.loadAsync([
require("./assets/images/algeria_flag.png"),
require("./assets/images/login_bg.jpg"),
require("./assets/images/road.jpg")
]),
Font.loadAsync({
// This is the font that we are using for our tab bar
...Icon.Ionicons.font,
...Icon.EvilIcons.font,
// We include SpaceMono because we use it in HomeScreen.js. Feel free
// to remove this if you are not using it in your app
"space-mono": require("./assets/fonts/SpaceMono-Regular.ttf"),
questrial: require("./assets/fonts/Questrial-Regular.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
PatuaOne: require("./assets/fonts/PatuaOne-Regular.ttf")
})
]);
};
_handleLoadingError = error => {
// In this case, you might want to report the error to your error
// reporting service, for example Sentry
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff"
}
});
You can't do this in render() method:
// As soon as app finishs loading and splash screen hides
// Check if user loggedIn
// Firebase.auth().onAuthStateChanged(user => {
// if (user) {
// this.setState({ isUserLogged: true });
// console.log(user.providerData[0].phoneNumber);
// } else {
// console.log("No user logged in yet!");
// }
// });
You add that in componentWillMount usually. As the error indicates, you are calling setState inside render which causes infinite loop.
EDIT:
Also you should unsubscribe from firebase on unmounting. That means you should do something like this this.firebaseUnsubscriber = Firebase.auth().onAuthStateChanged(user => {...}). In componentWillUnmount add if(this.firebaseUnsubscriber) this.firebaseUnsubscriber()
Any ideas why I am getting the following this "dispatch is not a function" error in my listEventsActionCreator function when it calls "dispatch(listEventsRequestedAction())" ???
If I comment out the lines in this method after the dispatch it actually then works which is strange.
Using react-create-app, with redux, typescript, thunk.
ERROR:
TypeError: dispatch(...) is not a function
CODE:
export function listEventsRequestedAction() {
return {
type: PlannerEventTypes.LIST_EVENTS_REQUESTED
}
}
export const listEventsReceivedAction = (events:PlannerEvent[]) => {
return {
type: PlannerEventTypes.LIST_EVENTS_RECEIVED,
events
}
}
export const listEventsErrorAction = (err:any) => {
return {
type: PlannerEventTypes.LIST_EVENTS_ERROR,
error: err
}
}
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction()) // <== ERROR: TypeError: dispatch(...) is not a function
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
package.json
{
"name": "planner",
"version": "0.1.0",
"private": true,
"dependencies": {
"#types/graphql": "^14.0.7",
"#types/react-redux": "^6.0.10",
"aws-amplify": "^1.1.19",
"aws-amplify-react": "^2.3.0",
"date-fns": "^1.30.1",
"eslint": "^5.9.0",
"konva": "^2.5.1",
"moment": "^2.22.2",
"moment-timezone": "^0.5.23",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-draggable": "^3.0.5",
"react-konva": "^16.6.31",
"react-moment": "^0.8.4",
"react-redux": "^5.1.1",
"react-scripts-ts": "3.1.0",
"redux": "^4.0.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
},
"devDependencies": {
"#types/jest": "^23.3.10",
"#types/node": "^10.12.10",
"#types/react": "^16.7.10",
"#types/react-dom": "^16.0.11",
"#types/redux-logger": "^3.0.7",
"typescript": "^3.2.1"
}
}
index.tsx
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { applyMiddleware, createStore } from 'redux'
import App from './App'
import './index.css'
import rootReducer from './reducers/index'
import registerServiceWorker from './registerServiceWorker'
import { createLogger } from 'redux-logger'
import thunkMiddleware from 'redux-thunk'
const loggerMiddleware = createLogger()
const store = createStore (
rootReducer,
applyMiddleware(
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware // neat middleware that logs actions
)
)
render(
<Provider store={store}>
<App testStr='test' />
</Provider>
,document.getElementById('root') as HTMLElement
);
registerServiceWorker();
The problem is because of the syntax that you followed. You don't have a semicolon after dispatch(listEventsRequestedAction()) and since you follow it up with (API.graphql(graphqlOperation(listEvents) as Promise<any>) while compiling it is evaluted as dispatch(listEventsRequestedAction())(API.graphql(graphqlOperation(listEvents) as Promise<any>) and hence it gives you the error.
Adding a semicolon after dispatch(listEventsRequestedAction()) would work
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction());
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
P.S. The semicolon is not required in Javascript and would not cause a
js error on its own. It could however cause an error if concatenating
with other scripts.
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.