I just added a sign in page and component to an example react app I'm working on, but any time I navigate to the new page (localhost:3000/signin), the page hangs and looking into the Chrome task manager, starts using 300+% CPU power. Nothing is printed to the console, and nothing ever shows up on the screen.
I know this can happen when there is some sort of call loop that tries to render infinitely, but I don't see where that could be happening in the code I have.
Here is my App.js:
import React from "react";
import { Switch, Route } from "react-router-dom";
import "./App.css";
import HomePage from "./pages/homepage/homepage";
import ShopPage from "./pages/shop/shopPage";
import Header from "./components/header/header";
import SignInAndSignUpPage from "./pages/signInSignUp/signInSignUp";
function App() {
return (
<div>
<Header />
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/shop" component={ShopPage} />
<Route path="/signin" component={SignInAndSignUpPage} />
</Switch>
</div>
);
}
export default App;
my SignIn/SignUp page (sign up not implemented yet):
import React from "react";
import SignIn from "../signInSignUp/signInSignUp";
import "./signInSignUp.scss";
const SignInAndSignUpPage = () => (
<div className="sign-in-and-sign-up">
<SignIn />
</div>
);
export default SignInAndSignUpPage;
and my SignIn component:
import React from "react";
import "./sign-in.styles.scss";
class SignIn extends React.Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
handleSubmit = event => {
event.preventDefault();
this.setState({ email: "", password: "" });
};
handleChange = event => {
const { value, name } = event.target;
this.setState({ [name]: value });
};
render() {
return (
<div className="sign-in">
<h2>I already have an account</h2>
<span>Sign in with your email and password</span>
<form onSubmit={this.handleSubmit}>
<input
name="email"
type="email"
onChange={this.handleChange}
value={this.state.email}
label="email"
required
/>
<input
name="password"
type="password"
value={this.state.password}
onChange={this.handleChange}
label="password"
required
/>
<input type="submit"> Sign in </input>
</form>
</div>
);
}
}
export default SignIn;
Thanks in advance.
I discovered that this issue was caused by a recursive import in another file. The component was importing itself by mistake, which caused infinite re-rendering. Always double-check your imports!
Related
I am developing a full-stack React application. At the frontend, I have a user registration form. I am using React Query to post the form data to the /api/users/register endpoint. Once the data is POSTed successfully, I redirect the user to the home(/) route.
Everything is working as expected; however, I am getting this message in the console:
I don't know what is causing this warning.
I would appreciate any help.
The code samples are as follows:
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "#tanstack/react-query";
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Router>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</Router>
);
App.js
import React from "react";
import { Routes, Route } from "react-router-dom";
import Header from "./components/Header";
import Home from "./components/Home";
import Register from "./components/Register";
import Login from "./components/Login";
const App = () => {
return (
<>
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
</Routes>
</>
);
};
export default App;
Register.js
import React from "react";
import { useNavigate } from "react-router-dom";
import { useMutation } from "#tanstack/react-query";
import axios from "axios";
import { useFormik } from "formik";
import * as Yup from "yup";
const Register = () => {
const navigate = useNavigate();
const mutation = useMutation((registerFormData) => {
return axios.post("/api/users/register", registerFormData);
});
const formik = useFormik({
initialValues: {
name: "",
email: "",
password: "",
},
validationSchema: Yup.object({
name: Yup.string()
.max(20, "Must be 20 characters or less")
.required("Name is required."),
email: Yup.string()
.email("Invalid email address")
.required("Email is required."),
password: Yup.string()
.min(5, "Must be 5 characters or more")
.required("Password is required."),
}),
onSubmit: (values) => {
mutation.mutate(values);
},
});
mutation.isSuccess && navigate("/");
return (
<div className="register-form-container">
<div>
<h1>Register</h1>
</div>
<form onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="name">Name</label>
<input
id="name"
name="name"
type="text"
{...formik.getFieldProps("name")}
/>
{formik.touched.name && formik.errors.name ? (
<span>{formik.errors.name}</span>
) : null}
</div>
<div>
<label htmlFor="email">Email</label>
<input
id="email"
name="email"
type="email"
{...formik.getFieldProps("email")}
/>
{formik.touched.email && formik.errors.email ? (
<span>{formik.errors.email}</span>
) : null}
</div>
<div>
<label htmlFor="password">Password</label>
<input
id="password"
name="password"
type="password"
{...formik.getFieldProps("password")}
/>
{formik.touched.password && formik.errors.password ? (
<span>{formik.errors.password}</span>
) : null}
</div>
<div>
<button type="submit">Register</button>
</div>
</form>
</div>
);
};
export default Register;
I guess its because you have a side effect on render phase of Register component.
Side effect
mutation.isSuccess && navigate("/");
You should handle your side effects in a useEffect hook.
useEffect(() => {
if (mutation.isSuccess) navigate("/")
}, [mutation, navigate]);
React makes sure to run effects after the component's render phase is finished.
I am now working on routing after login in successfully. But got this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'navigate')
Here is the login page
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
loginName: "",
password: "",
loginNameError: null,
passwordError: null,
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
this.props.navigation.navigate("/employee")
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="input-container">
<label>User ID</label>
<input type="text" name="loginName" value={this.state.loginName} onChange={(e) => (this.setState({ loginName: e.target.value }))} />
<p>{this.state.loginNameError}</p>
</div>
<div className="input-container">
<label>Password</label>
<input type="password" name="password" value={this.state.password} onChange={(e) => (this.setState({ password: e.target.value }))} />
<p>{this.state.passwordError}</p>
</div>
<div className="button-container"><input type="submit" value="CONNECT"></input></div>
</form>
);
}
}
export default Login;
Here is the APP.js
function App() {
return (
<div class="page">
<BrowserRouter>
<Routes>
<Route path="/employee" element={<UserManagement />}></Route>
<Route path="/login" element={<Login />}></Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
how to solve this error?
Since react router v6 doesnt have withRouter
// https://reactrouter.com/docs/en/v6/getting-started/faq#what-happened-to-withrouter-i-need-it
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
// then in the Login class component you can consume withRouter
handleSubmit(event) {
event.preventDefault();
// consume `router` prop
this.props.router.navigate("/employee");
}
// Wrap Login in withRouter HOC to make sure `router` prop is available
export default withRouter(Login);
// export default Login;
This said, I would recommend using react-router with a function component, not a class component.
Because using of class component you can not use hooks!
but I think this work here:
this.props.history.push("/employee");
I've got a switch in App.js to render different body components. "Landing" is the landing page body component. It's got a text field to enter a zip code, and when you click the submit button, it renders the "Events" page body component that displays some stuff.
When the Events component loads, I need it to be able to access the zip code that the user entered on the Landing page, so I lifted "zip" to App.js, which is the parent of Landing and Events.
I'm using Route and Switch so I can render the different body components. It's not getting that far though:
TypeError: this.props.onZipChange is not a function
No clue why it doesn't recognize onZipChange as a function in App.js. I won't bother showing the Events.js file because it's not even being rendered before I get the TypeError. The second I try to type into the input box in Landing.js, it triggers the input box's onChange attr, which calls this.handleChangeZip, which tries to call App.js' onZipChange function through this.props, which it's not recognizing.
Any thoughts?
App.js:
import React, { PropTypes, Component } from "react";
import "./styles/bootstrap/css/bootstrap.min.css";
import "./styles/App.css";
import "./index.css";
import Header from "./routes/Header";
import Body from "./routes/Body";
import { Switch, Route, NavLink } from "react-router-dom";
import Landing from "./routes/Landing";
import Events from "./routes/Events";
import Help from "./routes/Help";
class App extends Component {
constructor(props) {
super(props);
this.state = { zip: "" };
this.handleZipChange = this.handleZipChange.bind(this);
}
handleZipChange = newZip => {
this.setState({ zip: newZip });
};
render() {
const currZip = this.state.zip;
return (
<div className="App">
<Header zip={currZip} />
<Switch>
<Route
exact
path="/"
render={props => <Landing {...props} zip={currZip} />}
onZipChange={this.handleZipChange}
/>
<Route
exact
path="/Events"
render={props => <Events {...props} zip={currZip} />}
onZipChange={this.handleZipChange}
/>
<Route exact path="/Help" component={Help}></Route>
</Switch>
</div>
);
}
}
export default App;
Landing.js:
import { Redirect } from "react-router-dom";
import React from "react";
import "../styles/App.css";
class Landing extends React.Component {
constructor(props) {
super(props);
this.state = { value: "", toEvents: false };
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChangeZip = this.handleChangeZip.bind(this);
}
handleChangeZip(e) {
this.props.onZipChange(e.target.value);
}
handleSubmit(event) {
this.setState(() => ({
toEvents: true
}));
event.preventDefault();
}
render() {
if (this.state.toEvents === true) {
return <Redirect to="/Events" />;
}
return (
<div>
<div className="main-body">
<div className="main-question" id="thisfontonly">
What city are you looking for?
</div>
<div className="textbar-and-button">
<input
onChange={this.handleChangeZip}
value={this.props.zip}
type="text"
name="city"
id="citylabel"
style={{ fontSize: "24pt" }}
className="rcorners"
/>
<div className="buttons">
<input
onClick={this.handleSubmit}
type="submit"
name="submit"
value="Go!"
id="submit"
className="button"
/>
</div>
</div>
</div>
</div>
);
}
}
export default Landing;
This is My App.js where all the Routes define Under Router. It's work fine when i jump from one Link to other in those component that are not using redux. but when i click on Redux connected component it's render component but then when i click on any other Link they just change Url Not view.
This is App js File:-
import React, { useEffect, Fragment } from "react";
import { Router, Route, Switch } from "react-router-dom";
import history from "./history";
import Navbar from "./components/layouts/Navbar";
import Landing from "./components/layouts/Landing";
import Profiles from "./components/profiles/Profiles";
import Login from "./components/auth/Login";
import Register from "./components/auth/Register";
import { loadUser } from "./actions/auth";
import { useDispatch } from "react-redux";
const App = () => {
const dispatch = useDispatch(() => loadUser());
useEffect(() => {
dispatch(loadUser());
}, [dispatch]);
return (
<Router history={history}>
<Navbar />
<Route exact path='/' component={Landing} />
<section className='container'>
<Alert />
<Switch>
<Route exact path='/register' component={Register} />
<Route exact path='/login' component={Login} />
<Route path='/profiles' component={Profiles} />
</Switch>
</section>
</Router>
);
};
export default App;
Both Register And LogIn Workimg well when navigating through each other but when I jump to component that using redux profiles, it loads and work but after that when i want to jump from profiles to Register login they just change url not view.
this is My profiles file that using redux and creating issue.
import React, { Fragment, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getProfiles } from "../../actions/profile";
import Spinner from "../layouts/Spinner";
import ProfileItems from "./ProfileItems";
import { withRouter } from "react-router-dom";
const Profiles = () => {
const profile = useSelector(state => state.profile);
const { profiles, loading } = profile;
const dispatch = useDispatch(() => getProfiles());
useEffect(() => dispatch(getProfiles()), [dispatch]);
return (
<Fragment>
{loading ? (
<Spinner />
) : (
<Fragment>
<h1 className='large text-primary'>Developers</h1>
<p className='lead'>
<i className='fab fa-connectdevelop'></i> Browse and Connect With
Developers...
</p>
<div className='profiles'>
{profiles.length > 0 ? (
profiles.map(profile => (
<ProfileItems key={profile._id} profile={profile} />
))
) : (
<h4>profile not Found !!!...</h4>
)}
</div>
</Fragment>
)}
</Fragment>
);
};
export default withRouter(Profiles);
And These are My Login And Register component that are working well when navigate to each other. when they go to profiles after that when i click on link of them they just change urls in address bar but not changing view. It's Login page Register is similar to this..
import React, { Fragment, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { login } from "../../actions/auth";
import { Link, Redirect } from "react-router-dom";
const Login = () => {
const dispatch = useDispatch(() => login());
const isAuthenticated = useSelector(state
=>state.auth.isAuthenticated);
const [formData, setFormData] = useState({
email: "",
password: ""
});
const { email, password } = formData;
const onChange = e => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
const onSubmit = e => {
e.preventDefault();
dispatch(login(email, password));
};
if (isAuthenticated) {
return <Redirect to='/dashboard' />;
}
return (
<Fragment>
<h1 className='large text-primary'>Sign In</h1>
<p className='lead'>
<i className='fas fa-user'>Sign In Your Account!!!</i>
</p>
<form onSubmit={e => onSubmit(e)} className='form'>
<div className='form-group'>
<input
type='email'
name='email'
placeholder='Enter Your Email'
value={email}
onChange={e => onChange(e)}
/>
</div>
<div className='form-group'>
<input
type='password'
name='password'
placeholder='Enter Your Password'
value={password}
onChange={e => onChange(e)}
/>
</div>
<div className='form-group'>
<input type='submit' value='LogIn' className='btn btn-primary' />
</div>
</form>
<p className='my-1'>
Don't have an Account <Link to='/register'>Sign Up</Link>
</p>
</Fragment>
);
};
export default Login;
I searched this alot and mostly got ans use withRouter I tried that one as u can see but still not working or maybe i am not using withRouter on correct component.
I'll do Provide any other information that you need to know about my code if you want and I am using react-redux hooks instead of using connect
I had faced the same problem in the past.
At that time I solve this issue with connected-react-router.
this is how to use the connected-react-router.
how to use connected-react-router
In my code I have a few checks after a user has entered some data, then I want to load the next route if everything is correct, what is the best way to do so?
This is my current Route page:
<Router history = {browserHistory}>
<Route exact path="/" component={() => <MainMenu userData={this.state.userData}/>}/>
<Route exact path="/login" component = {Login} />
<Route exact path="/pastMeetingsPlay/:meetingCode" component={(props) => <PastMeetingsPlay user={this.state.userData.UserID} {...props}/>} />
<Route exact path="/meetingMode/:meetingCode" component={(props) => <MeetingMode user={this.state.userData.UserID} {...props}/>} />
</Router>
the user submits a form then there inputs are checked and if all the required checks pass then it should load meetingMode page
EDIT:
import React, { Component } from 'react';
import './App.css';
import MeetingMode from'./MeetingMode';
import NavbarMenu from './Navbar';
import Popup from "reactjs-popup";
import axios from 'axios';
import {withRouter, history, Redirect, Route} from "react-router";
class MeetingModeLoad extends Component{
constructor(props)
{
super(props);
this.state ={
meeting:{},
value:0
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
async handleSubmit(event)
{
event.preventDefault();
let meetingLoadCode = this.state.value
try{
let getter = await axios.get(`https://smartnote1.azurewebsites.net/api/meetings/${meetingLoadCode}`)
let meetingLocal = getter.data
this.setState({meeting:meetingLocal})
if(meetingLocal.Status == 2)
{
console.log("please join meeting that is planned or under going")
}
else
{
console.log("/meetingMode/" + this.state.meeting.MeetingID);
this.props.history.push("/meetingMode/" + this.state.meeting.MeetingID)
}
}
catch(error)
{
console.error(error)
}
}
handleChange(event)
{
this.state.value = event.target.value
console.log(this.state.value)
}
render()
{
return(
<div>
<Popup
trigger={<button className="meetingModeButton" onClick={() => this.handleClick}>Meeting Mode</button>}
modal
closeOnDocumentClick>
<div className="newNote">
<header style={{background: "#F7941D" }}> Meeting Mode</header>
<form onSubmit={this.handleSubmit}>
<label> Enter Meeting Code :
<input type="text" name="type" className="inputBox" onChange={this.handleChange}/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
{console.log(this.state.meeting)}
</Popup>
</div>
)
}
}
export default withRouter (MeetingModeLoad)
Looks like you forgot to wrap your component into withRouter. It is mandatory to access the history prop
Place this in the component from which you try to push:
import { withRouter } from 'react-router'
...
export default withRouter(YourComponent);
And push by using this in your component:
this.props.history.push("/meetingMode/" + meetingCode);