redux-sagas-authentication-app
redux-sagas-authentication-app copied to clipboard
this doesn't work with react router v4
Awesome tutorial but doesn't work with RRV4. Is it possible to modify this project to work with react router v4. this is what I am using?
{ "name": "vidhyasram_ui_v2", "version": "0.1.0", "private": true, "dependencies": { "history": "^4.6.3", "material-ui": "^0.18.6", "moment": "^2.18.1", "prop-types": "^15.5.10", "react": "^15.6.1", "react-datepicker": "^0.51.0", "react-dom": "^15.6.1", "react-redux": "^5.0.5", "react-router": "^4.1.1", "react-router-dom": "^4.1.1", "react-tap-event-plugin": "^2.0.1", "redux": "^3.7.1", "redux-form": "^6.8.0", "redux-saga": "^0.15.4" }, "devDependencies": { "react-scripts": "1.0.10" }, "scripts": { "start": "PORT=3001 react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } }
Hey @sanjeevghimire, good question! I've had a few ask me, and not that I'm aware of at the moment. I don't currently have plans to move anything to RRv4 until they get react-router-redux up-to-speed:
https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux
And once they do, I'm not sure how it will play with Redux Sagas - I haven't had the chance to fool around with the two together yet. If you find any clear cut path to migration I would LOVE to know though.
I'm using RRv4 and was able to get this working. Still hacking around with it, so maybe I'll run into issues... but so far, I can perform login, store token to local storage, and perform auth checks on my routes and direct/redirect accordingly.
FWIW, I didn't read the tutorial. Simply looked at source code and integrated it with my existing app.
Ah nice @mjoyce91! I'd love to see more.
@mjoyce91 can you share the code? i'm also using RRv4
Using it in this project I'm working on. (Be sure to stay within that branch).
I have this code: import React, {Component} from 'react'; import {connect} from 'react-redux'; import {reduxForm, Field} from 'redux-form'; import PropTypes from 'prop-types';
import { TextField } from 'redux-form-material-ui'; import Checkbox from 'material-ui/Checkbox'; import RaisedButton from 'material-ui/RaisedButton';
import loginRequest from '../../actions/loginActions';
//field validations import required from '../form-validation/required'; import email from '../form-validation/email'
class Login extends Component {
// Pass the correct proptypes in for validation static propTypes = { handleSubmit: PropTypes.func, loginRequest: PropTypes.func, pristine: PropTypes.bool, login: PropTypes.shape({ requesting: PropTypes.bool, successful: PropTypes.bool, messages: PropTypes.array, errors: PropTypes.array, }), }
componentDidMount() { this.refs.name // the Field .getRenderedComponent() // on Field, returns ReduxFormMaterialUITextField .getRenderedComponent() // on ReduxFormMaterialUITextField, returns TextField .focus(); // on TextField }
// Remember, Redux Form passes the form values to our handler
// In this case it will be an object with email
and password
submit = (values) => {
this.props.loginRequest(values)
}
render (){
const {
handleSubmit,
pristine,
login: {
requesting,
successful,
messages,
errors,
},
} = this.props
return (
BTW what is the use of client/ in this app?
Hey @sanjeevghimire - Client is a portion of the reducer that's general to every view (vs it being a remade each time). It's there to hold general user data, authentication, settings, etc.
@jcolemorrison Thanks for verifying. When logged in the client has token but when i refresh the page or access any other page which needs to have access to client its reset. Do you know what the problem could be?
the reason i need the client state here is to show login/register vs logout
import {connect} from 'react-redux';
import AvatarDropdown from '../components/avatarDropdown.js';
import Notification from './notification.js';
import RaisedButton from 'material-ui/RaisedButton';
import {Link, withRouter} from 'react-router-dom'
class Header extends Component {
state = {
logged: false,
};
handleChange = (event, logged) => {
this.setState({logged: logged});
};
render () {
const style = {
background: this.props.colorHeaderBanner.color
}
console.log(this.props.client.token); // this prints false
if (this.props.client.token){
return (
<header style={style} className="an-header">
<div className="header-right">
<Notification/>
<AvatarDropdown/>
</div>
</header>
)
}else{
return (
<header style={style} className="an-header">
<div className="header-right">
<NotLoggedHeader/>
</div>
</header>
)
}
}
}
const NotLoggedHeader = (props) => (
<div>
<Link to="/login">
<RaisedButton label="Login" primary={true} style={style} />
</Link>
<Link to="/register">
<RaisedButton label="Register" secondary={true} style={style} />
</Link>
</div>
);
const style = {
margin: 3,
};
function mapStateToProps (state) {
return {
colorHeaderBanner: state.headerBAnnerActiveStyle,
client : state.client
}
}
export default withRouter(connect(mapStateToProps)(Header));
@jcolemorrison this code doesn't work if i go to console and remove the token. it still thinks its authenticated. how can we handle that?
@sanjeevghimire Sorry, missed this - you're removing the token from localstorage right?
@jcolemorrison yes. is it possible to call logout from check-auth.js if so how can we do that? and btw i am using react router 4. this is how i have done it 👍
privateRoute.js import React from 'react'; import { Redirect, Route } from 'react-router-dom'; import {isLoggedIn} from '../utils/check-auth';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={ props => (
isLoggedIn() ? (
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
export default PrivateRoute;
check-auth.js import jwt_decode from 'jwt-decode'; import {CLIENT_UNSET} from '../client/constants'; import
export function isLoggedIn () {
// attempt to grab the token from localstorage
const storedToken = localStorage.getItem('token')
var decoded = jwt_decode(storedToken);
let now = new Date().getTime();
// if it exists
if (!storedToken) {
logout();
return false;
}
if(now > decoded.expiration){
logout();
return false;
}
return true
}
function logout() {
return {
type: CLIENT_UNSET
}
}
the problem here is logout is not working
@sanjeevghimire Thanks for sharing so much.
The problem though, is likely RRv4 (although I'm not 100% positive). RRv4 is very different from 3, and honestly haven't done any deep diving with it yet. Because all of the authentication/authorization is handled through RRv3's onEnter methods.
Additionally, from your code, it seems like you've extended it quite a bit (which is awesome). Because of this, I'm lacking some context as to why this would be failing.
BUT - in your code, logout isn't working because it has to be dispatch
'ed. I don't see any sign of that code calling redux
's dispatch
. Therefore, the CLIENT_UNSET
action isn't actually being sent through to the Saga. Instead it's just returning a plain Object. So it should be more like dispatch(logout())
.
Finally, if that doesn't work, it's like because of the differences in using Redux Saga with React Router 4. There's a big thread here on it:
https://github.com/ReactTraining/react-router/issues/3972
@sanjeevghimire I'm also using RRv4 and got it working, but still haven't yet implemented the log out functionality. Here's my repo, I hope it helps.
@jcolemorrison Great tutorial dude!, got me started in the right path with react. When can we expect part 3? 😊. Keep up the good work!.
This is super helpful @webjunkie01 thanks for sharing.
For part 3 - you should be able to find it here:
https://start.jcolemorrison.com/react-and-redux-sagas-authentication-app-tutorial-part-3/
@jcolemorrison Thanks, somehow I missed the link.
@mjoyce91 Link is broken( tree sprint-4 isn't exist) . Is it important to use exact tree "sprint-4"?