Reputation: 2415
I'm learning how to use Redux and am having an issue setting up the actions and reducers. Here is my setup:
Actions are here:
export const loginUser = (test) => {
return {
type:'loginUser',
loggedIn:true
}
}
export const toggleRegLog = (test) => {
return {
type:'toggleRegLog',
}
}
Reducers are here:
let initialState = [];
const userAuthReducer = (state = initialState,action) => {
switch (action.type) {
case 'loginUser':
let newState = [...state];
if(action.loggedIn) {
newState = "logged-in";
} else {
newState = "not-logged-in";
}
return newState;
break;
case:'toggleRegLog':
let newState = [...state];
return action.state;
break;
default:
return state;
}
}
export default userAuthReducer;
Combination of reducers is here in a file called index:
import {combineReducers} from 'redux';
import userAuthReducer from './reducers/userAuthReducer';
function lastAction(state = null, action) {
return action;
}
export default combineReducers({
userAuthReducer
});
Demo component:
import React, {Component} from 'react';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './actions/userAuthActions';
class App extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.props)
}
render() {
return (
<div>
<button onClick={this.props.loginUser()}></button>
</div>
);
}
const mapStateToProps = (state) => {
return {
userAuthReducer:state.userAuthReducer
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(authActions,dispatch);
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
}
I had the state working before in a more basic way but after looking at some more tutorials and deciding to introduce separate action creators (ie not just dispatching from my component straight to the reducer) and by introducing multiple cases in my reducer it doesn't seem to work anymore. The console.log(this.props)
on my component returns the actions as functions and states as undefined.
Can anyone spot where i've gone wrong?
Upvotes: 4
Views: 441
Reputation: 4090
You have so many errors in this project setup.
You should see them if you are running the code you posted
Constants (missed)
Constants are important to add consistency to your actions and reducers.
export const LOGIN_USER = 'loginUser';
export const TOGGLE_REG_LOG = 'toggleRegLog';
Actions
There is nothing wrong with your actions, just a couple of recommendations
.
import { LOGIN_USER, TOGGLE_REG_LOG } from '../constants/userAuthConstants';
export const loginUser = (loggedIn = true) => {
return {
type: LOGIN_USER,
payload: {
loggedIn
}
}
}
export const toggleRegLog = () => {
return {
type: TOGGLE_REG_LOG,
}
}
Reducers
You have an error in case: toggleRegLog:
declaration.
Recommendations:
Object.assign
instead of spread operatornewState
.
import { LOGIN_USER, TOGGLE_REG_LOG } from '../constants/userAuthConstants';
const initialState ={
userLoginStatus: 'not-logged-in'
};
const userAuthReducer = (state = initialState, action) => {
switch (action.type) {
case LOGIN_USER: {
const userLoginStatus = action.payload.loggedIn ? 'logged-in' : 'not-logged-in';
const newState = Object.assign(state, {
userLoginStatus
});
return newState;
}
case TOGGLE_REG_LOG: {
let newState = Object.assign({}, state, {}); // do what you need here
return newState;
}
default:
return state;
}
}
export default userAuthReducer;
Component
When you attach the onClick
event in the button you are executing the loginUser
function when it's expecting a function callback, instead, pass the loginUser
without executing it so when user clicks the button the action will be dispatched
Recommendations:
constructor
if you will not do anything within it.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { loginUser } from './actions/userAuthActions';
class App extends Component {
componentDidMount() {
console.log(this.props);
}
render() {
const { userLoginStatus, loginUser } = this.props;
return (
<div>
<p> User status: {userLoginStatus}</p>
<button onClick={loginUser}>click me</button>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
userLoginStatus: state.userAuthReducer.userLoginStatus
};
};
const mapDispatchToProps = (dispatch) => {
return {
loginUser: () => dispatch(loginUser())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Before you start testing any library/framework make sure, you are following the best practices, also that your code does not contain any error otherwise you can start having nightmares with your code.
Upvotes: 4
Reputation: 5243
Actions: Here I have added the newState payload to the action as it is being used in the reducer.
export const loginUser = () => {
return {
type:'loginUser',
loggedIn:true
}
}
export const toggleRegLog = () => {
return {
type:'toggleRegLog',
newState: xyz, //whatever you want it to be
}
}
Reducers: Here I have changed your initial state to a json object which has a field for loginStatus. You can use the same object to track other things by adding other fields. I have set the initial state of the field to "not-logged-in". In the reducer, the initail state is spread in a new object using the spread operator and the fields that are to be updated are overwritten.
let initialState = {
loginStatus:"not-logged-in",
//other stuff
};
const userAuthReducer = (state = initialState,action) => {
switch (action.type) {
case 'loginUser':
let newState = {};
if(action.loggedIn) {
newState = {...state, loginStatus:"logged-in"};
} else {
newState = {...state, loginStatus:"not-logged-in"};
}
return newState;
break;
case:'toggleRegLog':
return {...state, loginStatus:action.newState};
break;
default:
return state;
}
}
export default userAuthReducer;
The App component:
import React, {Component} from 'react';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './actions';
class App extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.props)
}
render() {
return (
<div>
<button onClick={this.props.loginUser}></button>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
userAuthReducer:state.userAuthReducer
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(authActions,dispatch);
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
Upvotes: 0