Matched leaf route at location - reactjs

// I don't know why I am getting this error.
// When I tried to Route using element,
// I was able to use the routes.
// But when I tried using render inside the route to use component
// along with props I am getting error as below-
.
// "When I try to go to "localhost:3000" I get an error saying-
// Error:
// Matched leaf route at location / does not have an element. This means it will render an
// "" with a null value by default resulting in an "empty" page.
// Also, And I am unable to get my "contact list" and also add contact form."
1.This is my App.js
-----------------------------------------------------
function App() {
const LOCAL_STORAGE_KEY='contacts';
const [contacts,setContacts]=useState([]);
const addContactHandler=(contact)=>{
console.log(contact);
setContacts([...contacts,{id:uuidv4(), ...contact}]);
};
const removeContactHandler= (id)=>{
const newContactList = contacts.filter((contact)=>{
return contact.id !== id;
});
setContacts(newContactList);
};
useEffect(()=>{
const retriveContacts = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY));
if(retriveContacts) setContacts(retriveContacts);
},[]);
useEffect(()=>{
localStorage.setItem(LOCAL_STORAGE_KEY,JSON.stringify(contacts));
},[contacts]);
return (
<div className="">
<Router>
<Header/>
<Routes>
<Route
exact path="/"
render={(props)=>(
<ContactList
{...props}
contacts={contacts}
getContactId={removeContactHandler}
/>
)}
/>
<Route exact path="/add"
render={(props)=>(
<AddContact {...props} addContactHandler={addContactHandler}
/>
)}
/>
{/* <Route exact path="/add" element= {<AddContact
addContactHandler={addContactHandler}/>}/>
<Route
exact path="/"
element={
<ContactList
contacts={contacts}
getContactId={removeContactHandler}/>}/> */}
</Routes>
</Router>
</div>
);
}
export default App;
2.This is my AddContact.js
It consists of basic form submit methods using states.
-----------------------------------------------------------------------------
class AddContact extends React.Component{
state={
name:"",
email:"",
};
add=(e)=>{
e.preventDefault();
if(this.state.name==="" || this.state.email===""){
alert("All the input fields are empty!");
return;
}
this.props.addContactHandler(this.state);
this.setState({name:"",email:""});
}
render(){
return(
<>
<form className="form-group" onSubmit={this.add}>
<div className="column">
<label for="name">Full Name</label>
<input
type="text"
className="form-control"
id="fullname"
placeholder="Full Name"
onChange={(e)=>this.setState({name:e.target.value})}/>
</div>
<div className="form-group ">
<label for="email">Email address</label>
<input
type="email"
className="form-control"
id="email"
aria-describedby="emailHelp"
placeholder="Enter email"
onChange={(e)=>this.setState({email:e.target.value})}/>
</div>
<br/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</>
)
}
}
export default AddContact
-----------------------------------------------------------------
3.This is my ContactList.js
---------------------------------------------------------------
const ContactList = (props) => {
console.log(props);
const deleteContactHandler=(id)=>{
props.getContactId(id);
};
const renderContactList = props.contacts.map((contact)=>{
return(
<ContactCard
contact={contact}
clickHandler={deleteContactHandler}
key={contact.id}/>
)
})
return (
<>
<br/>
<div className=''>
<h2>Contact List</h2>
<Link to="/add">
<button className='btn btn-warning mb-2'>Add Contacts</button>
</Link>
{renderContactList}
</div>
</>
)
}
export default ContactList;
-----------------------------------------------------------

In react-router-dom#6 there are no longer any route props and the Route component API changed, there are no longer any component and render and children function props. They were replaced by a single element prop taking a ReactNode, a.k.a. JSX, as a value.
Route
declare function Route(
props: RouteProps
): React.ReactElement | null;
interface RouteProps {
caseSensitive?: boolean;
children?: React.ReactNode;
element?: React.ReactNode | null;
index?: boolean;
path?: string;
}
By using a non-existent prop, i.e. render, no content was returned to be rendered on the currently matching "/" path.
Use the element prop for all routed content.
Example:
<Router>
<Header/>
<Routes>
<Route
path="/"
element={(
<ContactList
contacts={contacts}
getContactId={removeContactHandler}
/>
)}
/>
<Route
path="/add"
element={<AddContact addContactHandler={addContactHandler} />}
/>
</Routes>
</Router>

Related

How to navigate to another page in reactJS using SubmitHandler?

I wan to navigate to the dashboard page immediately after I submit the details. Here this is my CreateMonthWallet class where I am creating different for different months. Inside this create form all the information are there which are needed to be collected by the user. Once the user click the create button, the user should navigate back to the Dashboard page. Below given is the code of CreateMonthWallet class. When I run the code, once after clicking the cleate button it gives me the message of error but the data is updated to database but still its showing the message of error on the localhost page and doesn't navigating to the dashboard.
import axios from 'axios'
import React, { Component } from 'react'
class CreateMonthWallet extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
accountNumber: '',
description: '',
priority: ''
}
}
changeHandler = (event, fieldName) => {
this.setState({
[fieldName]: event.target.value
})
}
submitHandler = (event) => {
const newWallet = {
name: this.state.name,
accountNumber: this.state.accountNumber,
description: this.state.description,
priority: this.state.priority
}
axios.post('http://localhost:8080/monthwallet', newWallet)
.then((res) => {
this.props.history.push('/Dashboard')
}).catch((err) => {
alert("Error")
})
event.preventDefault()
}
render() {
return (
<div className="project">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h5 className="display-4 text-center">Create Wallet</h5>
<hr />
<form onSubmit={(event)=>this.submitHandler(event)}>
<div className="form-group">
<input type="text" onChange={(event) => this.changeHandler(event, "name")} className="form-control form-control-lg " placeholder="Account Name" />
</div>
<div className="form-group">
<input type="text" onChange={(event) => this.changeHandler(event, "accountNumber")} className="form-control form-control-lg" placeholder="Account No" />
</div>
<div className="form-group">
<textarea onChange={(event) => this.changeHandler(event, "description")} className="form-control form-control-lg" placeholder="Description"></textarea>
</div>
<div className="form-group">
<select className="form-control form-control-lg" onChange={(event) => this.changeHandler(event, "priority")}>
<option value={3}>Display Priority</option>
<option value={1}>High</option>
<option value={2}>Medium</option>
<option value={3}>Low</option>
</select>
</div>
<input type="submit" className="btn btn-dark btn-block mt-4" value="Create" />
</form>
</div>
</div>
</div>
</div>
)
}
}
export default CreateMonthWallet
Edit:
Adding the content of function App to the question. As it became relevant.
function App() {
return (
<Router>
<div>
<Nav />
<Routes>
<Route path="/" element={<Welcome />} exact />
<Route path="/Dashboard" element={<Dashboard />} exact />
<Route path="/CreateMonthWallet" element={<CreateMonthWallet />} exact />
<Route path="*" element={<NotFound />} exact />
</Routes>
</div>
</Router>
)
}
Issue
react-router-dom#6 removed the route props, so there should be some sort of error in the console along the lines of can't access property "push" of undefined when trying to execute this.props.history.push('/Dashboard'). The history object was replaced by a navigate function in RRDv6, accessible via the useNavigate hook.
Solution
You can either convert CreateMonthWallet into a React function component so it can use React hooks, or you can create a custom withRouter Higher Order component to inject the navigate function as a prop.
Convert to React function component
import axios from 'axios'
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
const CreateMonthWallet = () => {
const navigate = useNavigate();
const [state, setState] = useState({
name: '',
accountNumber: '',
description: '',
priority: ''
});
const changeHandler = (event) => {
const { name, value } = event.target;
setState(state => ({
...state,
[name]: value
}))
}
const submitHandler = (event) => {
event.preventDefault();
axios.post('http://localhost:8080/monthwallet', state)
.then((res) => {
navigate('/Dashboard');
})
.catch((err) => {
alert("Error");
});
}
return (
<div className="project">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h5 className="display-4 text-center">Create Wallet</h5>
<hr />
<form onSubmit={submitHandler}>
<div className="form-group">
<input
type="text"
name="name"
onChange={changeHandler}
className="form-control form-control-lg"
placeholder="Account Name"
value={state.name}
/>
</div>
<div className="form-group">
<input
type="text"
name="accountNumber"
onChange={changeHandler}
className="form-control form-control-lg"
placeholder="Account No"
value={state.accountNumber}
/>
</div>
<div className="form-group">
<textarea
name="description"
onChange={changeHandler}
className="form-control form-control-lg"
placeholder="Description"
value={state.description}
/>
</div>
<div className="form-group">
<select
className="form-control form-control-lg"
name="priority"
onChange={changeHandler}
value={state.priority}
>
<option value={3}>Display Priority</option>
<option value={1}>High</option>
<option value={2}>Medium</option>
<option value={3}>Low</option>
</select>
</div>
<input
type="submit"
className="btn btn-dark btn-block mt-4" value="Create"
/>
</form>
</div>
</div>
</div>
</div>
);
};
export default CreateMonthWallet;
Create withRouter HOC
Follow the instructions at What happened to withRouter? I need it! part of the RRDv6 FAQ to create a replacement withRouter HOC.
Example:
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
const withRouter = Component => props => {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
Decorate the CreateMonthWallet with the new withRouter HOC and access this.props.router.navigate.
class CreateMonthWallet extends Component {
...
submitHandler = (event) => {
event.preventDefault();
const newWallet = { ...this.state };
axios.post('http://localhost:8080/monthwallet', newWallet)
.then((res) => {
this.props.router.navigate('/Dashboard');
})
.catch((err) => {
alert("Error")
});
}
render() {
return (
...
);
}
}
export default withRouter(CreateMonthWallet);
Looks like you did not create a history variable yet. It's a piece of cake.
This variable that you are going to create, named history, will be responsible for storing the history of your browsing within your app.
With history you earn the ability to goBack(), for example. Notice that react-router is now favoring navigate instead. You can have a look later at the link below later for upgrading to newer versions.
react-router go back a page how do you configure history?
But let's keep ourselves in the problem here.
import {BrowserRouter, } from "react-router-dom";
import { createBrowserHistory } from 'history';
function App() {
const history = createBrowserHistory() //creates the variable history
return (
<BrowserRouter>
<div>
<Nav />
<Routes>
<Route path="/" element={<Welcome />} exact />
<Route path="/dashboard" element={<Dashboard history={history}/>} exact /> //passes it down to child component
<Route path="/createmonthwallet" element={<CreateMonthWallet history={history}/>} exact /> //passes it down to child component
<Route path="*" element={<NotFound />} exact />
</Routes>
</div>
</BrowserRouter>
)
}
What we did here:
Create a history object by importing createBrowserHistory from history. Use 'npm install history' if you do not have it yet.
Defining the variable inside your App function.
Pass it down as 'props' in your Route.
Now, your component will have access to this.props.history and you the error should go away.
As sidenotes, prefer using function components anywere in your code. Much easier to read, write, and much more flexible. Also, avoid using uppercase letters in path. something like path="wallet/month/create" would look more elegant in the long term cause you could have "wallet/month/update", "wallet/month/delete" and so on

React Router v6 Button onclick Navigate vis class components

Trying to port an application from router v2 to router v6.
Everything I see everywhere is hooks.
Tried to make a custom withRouter, "Hooks can only be called inside of the body of a function component."
The button in question
<YAButton
onClick={this.goToForgotPassword.bind(this)}
size="tiny"
style={YALogin.styles.forgotPassword}
type="text"
>
the function it calls
goToForgotPassword() {
this.props.navigate(`/forgot${isEmail(this.state.emailAddress) ?
`?emailAddress=${encodeURIComponent(this.state.emailAddress)}` :
''
}`);
}
the export at the bottom of the jsx file, perhaps something is amiss here?
export default connect(YALogin.mapStateToProps, YALogin.mapDispatchToProps)(Radium(withRouter(YALogin)));
and my withRouter
export const withRouter = (Component) => {
const Wrapper = (props) => {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return (
<Component
{...props}
navigate={navigate}
location={location}
params={params}
/>
);
};
return Wrapper;
};
Clearly I can't use hooks, but I also can't change the entire application over to function based components.
How do click "Forgot Password" button to go the
`/forgot${isEmail(this.state.emailAddress) ?
`?emailAddress=${encodeURIComponent(this.state.emailAddress)}` :
''
}`
edit: The render().
render() {
return (
<main
className="splash"
style={{
backgroundImage: `url(${window.__configuration.cdn}/splash/splash.jpg)`
}}
>
<form
className="stripped"
onSubmit={this.sendLoginRequest.bind(this)}
>
{/* Render the application logo */}
<div className="dual-logo">
<img
src={`${window.__configuration.cdn}/logos/logo-redacted-y-negative.svg`}
className="redacted-logo"
alt="Weemarkable"
/>
<div className="logo-divider"></div>
<img
src={`${window.__configuration.cdn}/logos/logo-weemarkable-negative-${Translator.getLang()}.svg`}
className="weemarkable-logo"
alt="Weemarkable"
/>
</div>
{/* Set inner html to allow non-breaking-space tags to render */}
<p className="tagline"
dangerouslySetInnerHTML={{__html: Translator.translate("General.Tagline")}}></p>
<fieldset>
{/* Render an alert if the login has failed for any reason */}
{
this.props.loginError !== null ?
<YAAlert type="E">
<span>{this.state.errorMessage}</span>
</YAAlert> :
null
}
{/* Collect the email address from the user */}
<YAInput
type="email"
className="stripped-input"
noBaseStyles
onChange={this.onChange.bind(this, 'emailAddress')}
placeholder={Translator.translate("General.YourEmail")}
value={this.state.emailAddress}
/>
{/* Collect the password from the user */}
<YAInput
type="password"
className="stripped-input"
noBaseStyles
onChange={this.onChange.bind(this, 'password')}
placeholder={Translator.translate("Password.Password")}
value={this.state.password}
/>
<div style={YALogin.styles.controls}>
{/* Button which submits the login request to the server */}
<div>
<YAInput
type="submit"
className={classNames('btn-stripped', {disabled: !this.isFormValid()})}
noBaseStyles
value={Translator.translate("MainPage.SignIn")}
/>
</div>
{/* Button which takes the user to the forgot password screen */}
<div>
<YAButton
onClick={() => useNavigate()(`/forgot${isEmail(this.state.emailAddress) ? `?emailAddress=${encodeURIComponent(this.state.emailAddress)}` : ''}`)}
size="tiny"
style={YALogin.styles.forgotPassword}
type="text"
>
{Translator.translate("MainPage.ForgotPassword")}
</YAButton>
|
<YAButton
onClick={this.goToForgotPassword.bind(this)}
size="tiny"
style={YALogin.styles.forgotPassword}
type="text"
>
{Translator.translate("MainPage.TOU")}
</YAButton>
</div>
</div>
</fieldset>
</form>
{/* Render footer logo */}
<footer className="brand-bar login">
<img
src={`${window.__configuration.cdn}/logos/logo-redacted-of-hamilton-${window.__configuration.langCode}.svg`}
className="footer-logo"
alt="redactedof redacted| redacted| Brantford"
/>
</footer>
</main>
);
}
}

react-router-dom how to redirect after button click in component

I have login component and after user singin i will got data from express server with fetch that will say all okay i want to redirect user to main page.I didn't find anything that i may use with react-router-dom to redirect user. First thing i want to now,is redirect user after he click button, without data check
this is how my Routes
ReactDOM.render(
<div>
<div><div className="nav">
<BrowserRouter>
<div className="shapka">
<Link to={linkToLogin} className="login">Войти в профиль</Link>
</div>
<div className="navItems">
<Link to='/Rings' className="navItem">Кольца</Link>
<Link to='/Earrings' className="navItem">Серёжки</Link>
<Link to='/' className="navItem">Главная страница</Link>
<Link to='/Bracelets' className="navItem">Браслеты</Link>
<Link to='/Necklace' className="navItem">Ожерелья</Link>
</div>
<Routes>
<Route path="/" element={<App/>}/>
<Route path="/Rings" element={<Rings/>}/>
<Route path="/EarRings" element={<EarRings/>}/>
<Route path="/bracelets" element={<Bracelets/>}/>
<Route path="/Necklace" element={<Necklase/>}/>
<Route path='/Profile' element={<Login/>}/>
<Route path="Register" element={<Register/>}/>
</Routes>
</BrowserRouter>
</div>
</div>
</div>,
document.getElementById('mainDiv')
);
and this is my component that located in other js file
login.addEventListener('click',e=>{
let login = document.getElementById('username')
let pwd = document.getElementById('password')
if(login.value !== '' && pwd.value !== ''){
sendToLogin({login:login.value,pwd:pwd.value})
}
})
}
render(){
return <div className="main" id="main">
<div className="registration-cssave">
<div className="form" >
<h3 className="text-center">Вход в систему</h3>
<div className="form-group">
<input className="form-control item" type="text" name="login" maxLength="15" id="inputLogin" minLength="4"
pattern="^[a-zA-Z0-9_.-]*$" id="username" placeholder="Логин" required />
</div>
<div className="form-group">
<input className="form-control item" type="password" name="password" minLength="6" id="password"
placeholder="Пароль" required/>
</div>
<div className="form-group">
<button className="btn btn-primary btn-block create-account" type="submit" id="btnEnter">Войти</button>
</div>
<div className="toRegister">
<a href="/Register" >Регистрация</a>
</div>
</div>
</div>
</div>
}
}
export default Login
You can use the useHistory hook from react-router-dom
import { useHistory } from 'react-router-dom';
function App () {
const history = useHistory();
async function logUser (userData) {
const res = await api.post("yourApi/login",{data});
if(res.status===200){
history.push("/");
}
}
render(
// Rendered parts
)
}
Additionally you can render a hidden Link component with display: "none", attach it to a ref and programmatically click it when the server response is okay. Like this:
const redirectToMain = useRef(null);
async function logUser (userData) {
const res = await api.post("yourApi/login",{data});
if(res.status===200){
redirectToMain.current.click()
}
}
render (
// *** other parts
<Link
to="/"
ref={redirectToMain}
style={{display: "none"}}
/>
)
for class components, at the first you should make a functional component then use HOC technical to use useNavigate react hook. like this:
withrouter.js:
import {useNavigate} from 'react-router-dom';
export const withRouter = WrappedComponent => props => {
return (<WrappedComponent {...props} navigate={useNavigate()}/>);
};
then use use it in other class components like this:
export default withRouter(Signin);
and use props for redirect like this:
this.props.navigate('/');

React-cookies with hooks

i'm using React-cookies, redux, redux-thunk and hooks.
I don't understand how to store the value of " token " as a cookie.
this is the Component App.js
<Provider store={store}>
<CookiesProvider>
<BrowserRouter>
<Switch>
<Route exact path="/release/:id" component={Release} render={() => (<Login cookies={this.props.cookies} />)} />
<Route exact path="/login" render={() => (<Login cookies={this.props.cookies} />)} component={Login} />
</Switch>
</BrowserRouter>
</CookiesProvider>
</Provider>
actually the Login component is made as hook
I receive the value of the token because of call made with this component
function Form({ handleSubmit, login }, props) {
const [token, setToken] = useState(undefined);
const onSubmit = (user) => {
login(user);
};
return (
<form onSubmit={handleSubmit(onSubmit)} className={styles.flexColumn}>
<div className={styles.username}>
<P>username</P>
<Field name="username" component="input" type="text" className={styles.input} />
</div>
<div className={styles.password}>
<P>password</P>
<Field
name="password"
component="input"
type="text"
className={styles.input}
/>
</div>
<div className={styles.downSection}>
<Flex>
<div>
<P>
Serve Aiuto?
</P>
</div>
<a href="#">
<div className={styles.contactLink}>
<P>Contattaci</P>
</div>
</a>
</Flex>
<Button type="submit" text="Accedi" />
</div>
</form>
);
}
Form.propTypes = {
handleSubmit: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
};
const mapStateToProps = (state, ownProps) => ({
cookies: ownProps.cookies,
}, console.log(ownProps));
const mapDispatchToProps = {
login: loginAction,
};
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
reduxForm({ form: 'login' }),
);
export default enhance(Form);
How could i store the value token as a cookie ? i got this value thanks to loginAction
I must use the library react-cookies.
Thanks.
Use a library for it...
Such as react-cookie.
You can simply do:
import {useCookie} from 'react-cookie'
And use cookies.
Take a look here

How to add error information empty field and redirect after login in ReactJS and Firebase?

I use react js, react-router, and firebase database. and I want to add error information if login field is empty and if success I want to redirect to dashboard, but it doesn't work
this code in router.js
<Route path="/" name="Home" component={Simple}>
<IndexRoute component={Login}/>
</Route>
<Route path="/dashboard" name="Home" component={Full}>
<IndexRoute component={Dashboard}/>
<Route path="/dashboard" name="Dashboard" component={Dashboard}/>
</Route>
this code in login.js
function setErrorMsg(error) {
return {
loginMessage: error
}
}
class Login extends Component {
state = { loginMessage: null }
handleSubmit = (e) => {
e.preventDefault()
login(this.email.value, this.password.value)
.catch((error) => {
this.setState(setErrorMsg('Invalid username/password.'))
})
}
resetPassword = () => {
resetPassword(this.email.value)
.then(() => this.setState(setErrorMsg(`Password reset email sent to ${this.email.value}.`)))
.catch((error) => this.setState(setErrorMsg(`Email address not found.`)))
}
render() {
return (
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<div className="input-group mb-3">
<span className="input-group-addon"><i className="icon-user"></i></span>
<input type="text" ref={(email) => this.email = email} className="form-control" placeholder="Email"/>
</div>
<div className="input-group mb-4">
<span className="input-group-addon"><i className="icon-lock"></i></span>
<input type="password" ref={(password) => this.password = password} className="form-control" placeholder="Password"/>
</div>
{
this.state.loginMessage &&
<div>
<span className="sr-only">Error:</span>
{this.state.loginMessage} Forgot Password?
</div>
}
<button type="button" className="btn btn-primary px-4">Login</button>
<button type="button" className="btn btn-link px-0">Forgot password?</button>
</form>
);
}
}
Quick thought is that you need to bind your onSubmit, like <form onSubmit={this.handleSubmit.bind(this)}>.
Using class ... extends doesn't do autobinding.
Another way I like to do it is to bind in my contructor function:
class Login extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
// your code here
}

Resources