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
Related
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
// 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>
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('/');
I am pretty new to Apollo and starting right with version 2.1.
I also use react-router but I don't know how to do a browserHistory.push after a mutation was completed. Here are parts of my code:
index.js
const client = new ApolloClient({
uri: "http://localhost:4000/graphql"
});
ReactDOM.render(
<ApolloProvider client={client}>
<AppContainer>
<BrowserRouter basename={basename}>
<I18nextProvider i18n={i18n}>
<Layout />
</I18nextProvider>
</BrowserRouter>
</AppContainer>
</ApolloProvider>,
document.getElementById('react_root')
)
};
In onCompleted I want to show a different page to tell user to check the emails. But I don't know how to do so.
RegistrationForm.js
import {browserHistory) from 'react-router';
const onCompleted = (data) => {
browserHistory.push("/de/register/check-email");
}
const RegistrationForm = () => {
return (
<Mutation mutation={REGISTER_USER}
onCompleted={onCompleted}
>
{(register, { data }) => (
<div>
<Form
onSubmit={onSubmit}
render={({ handleSubmit, pristine, invalid, values, variables }) => (
<form onSubmit={(e, ) => {
e.preventDefault();
register({
variables: {
input: {
username: values.username,
email: values.email,
password: values.password
}
}
});
}}
>
<div>
<label>Username</label>
<Field name="username" component="input" placeholder="Username" />
</div>
<div>
<label>Email</label>
<Field name="email" component="input" placeholder="Email" />
</div>
<div>
<label>Password</label>
<Field name="password" component="input" placeholder="Password" />
</div>
<button type="submit" >Submit</button>
</form>
)}
/>
</div>
)}
</Mutation>
);
};
Does anybody knows how to do so? Thanks a lot for your help.
Best regards
There's no export browserHistory in react-router, but there is a history prop.
If your component is immediately under a <Route>, you can use it like this:
const RegistrationForm = ({history}) => {
const onCompleted = (data) => {
history.push("/de/register/check-email");
}
return (
..
If your component is deeper in the tree, you can inject the history and other route props with withRouter, e.g.:
const RegistrationFormWrapped = withRouter(RegistrationForm);
or
export default withRouter(RegistrationForm);
And because onCompleted depends on a prop now and needs to be local, it makes sense to convert RegistrationForm to a class.
I think I found the solution. I passed history as a prop from the calling component and then went with:
const RegistrationFinalForm = ({ history }) => {
return (
<Mutation mutation={REGISTER_USER}
onCompleted={(data) => {
history.push("/de/register/check-email");
}}>
So I am developing a React + Redux app.
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={AppContainer}>
<IndexRoute component={Home}/>
<Route path="login" component={LoginContainer}/>
<Route path="protected" component={Protected} onEnter={checkUserIsLoggedIn}/>
<Route path="*" component={NotFound}/>
</Route>
</Router>
</Provider>
AppContainer.jsx
const App = function(props){
var isAuthenticated = props.login.isAuthenticated;
return <Grid>
<h1>Welcome to app!</h1>
<nav>
{isAuthenticated ? <Link to="/logout">Logout</Link> : <Link to="/login">Login</Link> }|
<Link to="/">Home</Link> |
<Link to="/protected">Protected</Link> |
</nav>
<div>
{props.children}
</div>
</Grid>
};
const mapStateToProps = (state) => {
var loginState = state.login;
return {
login: {
apiToken: loginState.apiToken,
isAuthenticated: loginState.isAuthenticated
}
}
};
const AppContainer = connect(
mapStateToProps
)(App);
Home, NotFound and Protected are stateless components, i.e.
const Home = (props) => <h2>Home</h2>;
While Login.jsx
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import { Row, Col, Panel, Button, Alert, Form, FormGroup, FormControl, InputGroup, Glyphicon } from 'react-bootstrap'
class Login extends Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
this.activateSignup = this.activateSignup.bind(this);
}
onSubmit (e) {
e.preventDefault();
let username = ReactDOM.findDOMNode(this.refs.username).value;
let password = ReactDOM.findDOMNode(this.refs.password).value;
this.props.onLoginSubmit(username, password);
}
activateSignup (e){
alert('does nothing for now');
}
render () {
return (
<Col style={{marginTop: "50px"}} md={6} mdOffset={3} sm={8} smOffset={2}>
<Panel header="Sign In" bsStyle="info">
<Col sm={12}>
{this.props.apiToken && <Alert bsStyle="success">
<strong>Welcome!</strong>
</Alert>}
</Col>
<Form horizontal onSubmit={this.onSubmit}>
<InputGroup style={{marginBottom: "25px", paddingTop: "15px"}}>
<InputGroup.Addon><Glyphicon glyph="user"/></InputGroup.Addon>
<FormControl ref="username"
type="text"
placeholder="username or email"
required/>
</InputGroup>
<InputGroup style={{marginBottom: "25px"}}>
<InputGroup.Addon><Glyphicon glyph="lock"/></InputGroup.Addon>
<FormControl ref="password"
type="password"
placeholder="password"
required/>
</InputGroup>
<InputGroup>
<FormGroup>
<Col sm={12}>
<Button id="btn-login" bsStyle="success" type="submit" disabled={this.props.isFetching}>Login</Button>
</Col>
</FormGroup>
<FormGroup>
<Col md={12}>
<div style={{borderTop: "1px solid#888", paddingTop: "15px", "fontSize": "85%"}}>
Don't have an account!{' '}
<a href="#" onClick={this.activateSignup}>
Sign Up Here
</a>
</div>
</Col>
</FormGroup>
</InputGroup>
</Form>
</Panel>
</Col>
)
}
}
Login.propTypes = {
isFetching: PropTypes.bool,
error: PropTypes.string,
apiToken: PropTypes.string
};
export default Login;
LoginContainer.jsx
import { connect } from 'react-redux'
import { fetchLogin } from '../actions/login-actions'
import Login from '../views/Login.jsx'
const mapStateToProps = (state) => {
return state.login
};
const mapDispatchToProps = (dispatch) => {
return {
onLoginSubmit: (username, password) => {
dispatch(fetchLogin(username, password))
}
}
};
const LoginContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Login);
export default LoginContainer
So, I don't know why this is happening but I think it is because of the misuse between Redux and ReactRouter.
My /login renders perfectly. However, whenever I go to another route, the children components are not rendered because App.props.children is always null when using AppContainer. However, if I change the route path "/" component to use App instead of AppContainer, children are rendered successfully.
What am I doing wrong?