I am trying to implement Twitter authentication with React/Redux/Node.js. The back-end part is working fine, since the front-end is getting the right data.
The problem I’m facing right now is at the front-end. More specifically, when the token is received after the successful authentication, an action is dispatched, so that the props
are updated as a consequence. However, this doesn’t happen. Here is the code:
Header.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import TwitterLogin from 'react-twitter-auth';
import { connect } from 'react-redux';
import { loginSuccess, logout } from './redux/actions/actions';
import 'bulma/css/bulma.css';
class Header extends Component {
constructor(props) {
super(props);
this.onSuccess = this.onSuccess.bind(this);
this.onFailed = this.onFailed.bind(this);
}
onSuccess = (response) => {
const token = response.headers.get('x-auth-token');
response.json().then(user => {
if (token) {
this.props.loginSuccess(user, token);
}
});
};
onFailed = (error) => {
alert(error);
};
logout = () => {
this.props.logout();
};
render() {
let content = this.props.isAuthenticated === true ?
(
<div>
<div>
<Link className="button is-primary" to="/profile">Profile</Link>
<button onClick={this.logout} className="button" >
Log out
</button>
</div>
</div>
) :
(
<TwitterLogin
loginUrl="http://localhost:5000/api/auth/twitter"
onFailure={this.onFailed} onSuccess={this.onSuccess}
requestTokenUrl="http://localhost:5000/api/auth/twitter/reverse"
className="button" />
);
return (
<header className="navbar has-shadow is-spaced">
<div className="container">
<div className="navbar-brand">
<h1 className="title is-4">
<Link to="/" className="navbar-item">
<strong>App</strong>
</Link>
</h1>
</div>
<div className="navbar-end">
<div className="buttons">
{content}
</div>
</div>
</div>
</header>
);
}
}
const mapStateToProps = ({token, user, isAuthenticated}) => ({token, user, isAuthenticated});
export default connect(
mapStateToProps,
{loginSuccess,
logout})(Header);
actions.js
export const loginSuccess = (user, token) => {
return (dispatch) => {
dispatch({type: 'LOGIN_SUCCESS', payload: {user, token}})
}
}
reducers.js
const initialState = {
token: null,
user: null,
isAuthenticated: false,
error: false
};
export default (state=initialState, action) => {
switch (action.type) {
case 'LOGOUT':
localStorage.removeItem('user');
return initialState;
case 'LOGIN_ERROR':
return {
...state,
error: true
}
case 'LOGIN_SUCCESS':
return {
token: action.payload.token,
user: action.payload.user,
isAuthenticated: true,
error: false
}
default:
return state;
}
}
store.js
import {applyMiddleware, createStore} from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducer';
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
export const store = createStoreWithMiddleware(reducer);
What am I missing here? Is there something missing in the onSuccess function?
Thanks!
2
Answers
I found the issue! I was declaring the
mapStateToProps
in the wrong way.The right code is the following:
Header.js
Here is the code where I combine the reducers:
reducer.js
By using this code, I'm able to see the props updated after the action is dispatched.
Thanks for your help!
Please try to replace
by: