我有以下redux模块:
import { Map, fromJS } from 'immutable'
import api from '../lib/api'
import config from '../config/application'
import storage from '../lib/storage'
import { history } from '../lib/create-store'
// Actions
const USER_LOGIN = 'ts/user/USER_LOGIN'
const USER_LOGIN_RESPONSE = 'ts/user/USER_LOGIN_RESPONSE'
const USER_LOGOUT = 'ts/user/USER_LOGOUT'
const CREATE_ACCOUNT_TEAM = 'ts/user/CREATE_ACCOUNT_TEAM'
const CREATE_ACCOUNT_TEAM_RESPONSE = 'ts/user/CREATE_ACCOUNT_TEAM_RESPONSE'
const RECEIVE_ACCESS_TOKEN = 'ts/user/RECEIVE_ACCESS_TOKEN'
const RECEIVE_USER = 'adsdean/user/RECEIVE_USER'
const initialState = Map({
accessToken: null,
loginPending: false,
loginError: false,
creatingAccountTeam: false,
creatingAccountTeamSuccess: false,
creatingAccountTeamError: Map({}),
profile: Map({
id: null,
email: null,
firstName: null,
lastName: null,
company: null,
mobile: null,
mobileShare: true,
dob: null
})
})
// Reducer
export default function user (state = initialState, action = {}) {
switch (action.type) {
case RECEIVE_ACCESS_TOKEN: {
storage.save('key', action.token)
api.setAuth(action.token)
return state.set('accessToken', fromJS(action.token))
}
case USER_LOGIN:
return state.set('loginPending', true)
case USER_LOGIN_RESPONSE: {
let nextState = state.set('loginPending', false)
if (action.status === 'success') {
nextState = nextState
.set('loginError', initialState.loginError)
} else {
nextState = nextState.set('loginError', action.error)
}
return nextState
}
case USER_LOGOUT: {
storage.delete('key')
api.setAuth(null)
return state.set('accessToken', null)
}
case CREATE_ACCOUNT_TEAM:
return state.set('creatingAccountTeam', true)
case CREATE_ACCOUNT_TEAM_RESPONSE: {
console.log(action)
let nextState = state.set('creatingAccountTeam', false)
if (action.status === 'success')
state.set('creatingAccountTeamSuccess', true)
else
nextState = nextState.set('creatingAccountTeamError', fromJS(action.error))
return nextState
}
case RECEIVE_USER:
return state
.setIn('profile', 'id', action.payload.id)
.setIn('profile', 'email', action.payload.email)
.setIn('profile', 'firstName', action.payload.first_name)
.setIn('profile', 'lastName', action.payload.last_name)
.setIn('profile', 'company', action.payload.company)
.setIn('profile', 'mobile', action.payload.mobile)
.setIn('profile', 'mobileShare', action.payload.mobile_share)
.setIn('profile', 'dob', action.payload.dob)
}
return state
}
// ==============================
// Action Creators
// ==============================
export const userLoginResponse = (status, error) => ({
type: USER_LOGIN_RESPONSE,
status,
error,
})
export const receiveAccessToken = token => ({
type: RECEIVE_ACCESS_TOKEN,
token
})
export const userCreateWithTeamResponse = (status, error) => ({
type: CREATE_ACCOUNT_TEAM_RESPONSE,
status,
error,
})
export const receiveUser = user => ({
type: RECEIVE_USER,
payload: user
})
export const getAccessToken = state =>
state.get('accessToken')
export const isLoggedIn = state =>
state.get('accessToken')
// ==============================
// SIDE EFFECTS
// ==============================
//
//
export const getUser = () => async dispatch => {
api.request.get('/user')
.then(response => {
dispatch(receiveUser(response.data))
})
.catch(error => {
})
}
export const userLogin = (username, password) => async dispatch => {
dispatch({ type: USER_LOGIN })
api.request.post('/oauth/token', {
username,
password,
'grant_type': 'password',
'client_id': config.clientId,
'client_secret': config.clientSecret,
})
.then(response => {
console.log(response)
const { access_token } = response.data
dispatch(userLoginResponse('success', null))
dispatch(receiveAccessToken(access_token))
dispatch(receiveUser(response.data))
window.gtag('event', 'login')
})
.catch(error => {
console.log(error)
dispatch(userLoginResponse('error', error))
})
}
export const userLogout = () => dispatch => {
dispatch({ type: USER_LOGOUT })
history.push('/')
window.gtag('event', 'logout')
//logFormSubmission('Logout')
}
export const userCreateWithTeam = (form) => async dispatch => {
dispatch({ type: CREATE_ACCOUNT_TEAM })
api.request.post('/account/register/team', {
email: form.email,
password: form.password,
'first_name': form.firstName,
'last_name': form.lastName,
company: form.company,
name: form.name,
location: form.location,
dob: form.dob,
mobile: form.mobile,
'mobile_share': (form.mobileShare === true) ? 1 : 0
})
.then(response => {
console.log(response)
dispatch(userCreateWithTeamResponse('success', null))
dispatch(userLogin(form.email, form.password))
window.gtag('event', 'create account and team')
window.gtag('set', {'user_id': response.data.id})
})
.catch(error => {
console.log(error.response)
dispatch(userCreateWithTeamResponse('error', error.response.data))
})
}
一切正常,直到我添加名为getUser
的副作用函数。一旦我从我的一个组件/容器中import { getUser } from '../../modules/user'
,我就会被
Error: Reducer "user" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.
一旦我注释掉导入,使用该模块的其他所有内容都会继续正常工作。那个新的副作用是什么,看起来和造成这个的其他副作用相同?
我的创建商店代码:
import { createStore, applyMiddleware, compose } from 'redux'
import { ConnectedRouter, routerReducer, routerMiddleware, push } from 'react-router-redux'
import createHistory from 'history/createBrowserHistory'
import { combineReducers } from 'redux-immutablejs'
import { fromJS, Map } from 'immutable'
import thunk from 'redux-thunk'
import user from '../modules/user'
const initialState = fromJS({})
const enhancers = []
const middleware = [
thunk,
routerMiddleware(history)
]
export const history = createHistory()
const reducer = combineReducers({
user,
router: routerReducer,
})
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
)
const store = createStore(
reducer,
initialState,
composedEnhancers
)
export default store
我可以通过将initialState Map直接移动到reducer的默认参数部分来修复错误......似乎在将它放在单独的const中时会产生错误。然而,在推出这个功能之前,它已经在这周工作了几个星期......
e.g
// Reducer
export default function user (state = Map({
accessToken: null,
loginPending: false,
loginError: false,
creatingAccountTeam: false,
creatingAccountTeamSuccess: false,
creatingAccountTeamError: Map({}),
profile: Map({
id: null,
email: null,
firstName: null,
lastName: null,
company: null,
mobile: null,
mobileShare: true,
dob: null
})
}), action = {}) {
答案 0 :(得分:1)
setIn语法不正确,嵌套路径需要位于[]
内。
.setIn(['profile', 'id'], action.payload.id)
.setIn(['profile', 'email'], action.payload.email)
.setIn(['profile', 'firstName'], action.payload.first_name)
.setIn(['profile', 'lastName'], action.payload.last_name)
.setIn(['profile', 'company'], action.payload.company)
.setIn(['profile', 'mobile'], action.payload.mobile)
.setIn(['profile', 'mobileShare'], action.payload.mobile_share)
.setIn(['profile', 'dob'], action.payload.dob)
也在
if (action.status === 'success')
state.set('creatingAccountTeamSuccess', true) . // <--
您错过了将此分配给nextState
,这可能会导致不一致