Redux 状态显示为 Map,无法访问 combineReducers 属性
Redux state show as Map, unable to access combineReducers properties
在 mapStateToProps 中,它应该像访问所需状态部分的键一样简单,并获取状态参数,但我无法这样做。
主要app.js文件
import React from 'react'
import ReactDom from 'react-dom'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router/immutable'
import { createBrowserHistory } from 'history'
import configureStore from './store/configureStore'
import App from './components/partials/App'
const history = createBrowserHistory()
const store = configureStore(history)
ReactDom.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App/>
</ConnectedRouter>
</Provider>,
document.getElementById('reactDiv')
)
configureStore.js
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router/immutable'
import thunkMiddleware from 'redux-thunk'
import { combineReducers } from 'redux-immutable'
import { connectRouter } from 'connected-react-router'
import AppReducer from './reducers/app'
const createRootReducer = history => combineReducers({
router: connectRouter(history),
app: AppReducer
})
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(history) {
const middleware = [routerMiddleware(history), thunkMiddleware]
const rootReducer = createRootReducer(history)
return createStore(rootReducer, composeEnhancers(applyMiddleware(...middleware)))
}
appReducer
/**
* App level reducer
*/
const initialState = {
accounts: [],
employees: []
}
const reducer = (state = initialState, action) => {
switch(action.type) {
case 'ACCOUNT_SELECTION_LIST_LOADED':
return {...state, accounts: action.payload}
case 'EMPLOYEE_SELECTION_LIST_LOADED':
return {...state, employees: action.payload}
}
return state
}
export async function fetchAccountsSelectionList(dispatch, getState) {
makeAjaxRequest('/getList/accounts', 'GET', null, response => {
const accounts = JSON.parse(response)
dispatch({type: 'ACCOUNT_SELECTION_LIST_LOADED', payload: accounts})
})
}
export async function fetchEmployeesSelectionList(dispatch, getState) {
makeAjaxRequest('/getList/employees', 'GET', null, response => {
const employees = JSON.parse(response)
dispatch({type: 'EMPLOYEE_SELECTION_LIST_LOADED', payload: employees})
})
}
export default reducer
主要组件(缩小以保存 space)
import React, { Component } from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import { LinkContainer } from 'react-router-bootstrap'
import { FormControl, InputGroup, Navbar, Nav, NavDropdown, NavLink } from 'react-bootstrap'
import { connect } from 'react-redux'
import { fetchAccountsSelectionList, fetchEmployeesSelectionList } from '../../store/reducers/app'
import Select from 'react-select'
class App extends Component {
constructor() {
super()
this.state = {
billId: '',
invoiceId: '',
manifestId: ''
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount() {
this.props.fetchAccountsSelectionList()
this.props.fetchEmployeesSelectionList()
}
handleChange(event) {
const {name, checked, value, type} = event.target
this.setState({[name]: type === 'checkbox' ? checked : value})
}
render() {
return (
<BrowserRouter>
<Navbar variant='dark' bg='dark' className={'navbar-expand-lg', 'navbar'}>
<LinkContainer to='/'>
<Navbar.Brand>Fast Forward Express v2.0</Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls='responsive-navbar-nav' />
<Navbar.Collapse id='responsive-navbar-nav'>
<Nav className='ml-auto'>
<NavDropdown title='Bills' id='navbar-bills'>
</NavDropdown>
<NavDropdown title='Invoices' id='navbar-invoices'>
</NavDropdown>
<NavDropdown title='Accounts' id='navbar-accounts' alignRight>
</NavDropdown>
<NavDropdown title='Employees' id='navbar-employees' alignRight>
</NavDropdown>
<LinkContainer to='/app/dispatch'><NavLink>Dispatch</NavLink></LinkContainer>
<NavDropdown title='Administration' id='navbar-admin' alignRight>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
<Switch>
<Route path='xxx' component={xxx}></Route>
</Switch>
</BrowserRouter>
)
}
}
const matchDispatchToProps = dispatch => {
return {
fetchAccountsSelectionList: () => dispatch(fetchAccountsSelectionList),
fetchEmployeesSelectionList: () => dispatch(fetchEmployeesSelectionList)
}
}
const mapStateToProps = state => {
return {
accounts: state.app.accounts,
employees: state.app.employees
}
}
export default connect(mapStateToProps, matchDispatchToProps)(App)
所以。当我注销 mapStateToProps 正在接收的“状态”时,它是一个地图,而不是一个对象,看起来像这样:
state results
为什么我的状态看起来不像我看过的任何教程?我一直无法找到任何其他这样的例子,除了一个说只是手动迭代的例子 - 但由于那不是“正确”的方式,我必须错误地配置商店
我应该注意到,开发人员工具似乎能够完美地访问状态,并反映出我期望看到的内容。为什么我无法访问 state.app.accounts
问题是您使用的两个包依赖于 Immutable.js 数据结构,而不是普通的 JS 对象:import { combineReducers } from 'redux-immutable'
和 import { routerMiddleware } from 'connected-react-router/immutable'。
特别是,来自 redux-immutable
的 combineReducers
将导致根状态对象成为 Immutable.js Map
实例,而不是普通对象,并且Map
实例有 .get()
和 .set()
方法而不是普通字段。
We strongly recommend against using Immutable.js in Redux apps at this point.
相反,您应该将您的状态写成纯 JS 对象和数组,并且您应该使用 our official Redux Toolkit package 来设置您的商店并编写您的缩减程序。
请阅读 Redux 核心文档中的官方 "Redux Essentials" and "Redux Fundamentals" 教程,了解如何使用 Redux Toolkit 编写 Redux 逻辑。
在 mapStateToProps 中,它应该像访问所需状态部分的键一样简单,并获取状态参数,但我无法这样做。
主要app.js文件
import React from 'react'
import ReactDom from 'react-dom'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router/immutable'
import { createBrowserHistory } from 'history'
import configureStore from './store/configureStore'
import App from './components/partials/App'
const history = createBrowserHistory()
const store = configureStore(history)
ReactDom.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App/>
</ConnectedRouter>
</Provider>,
document.getElementById('reactDiv')
)
configureStore.js
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router/immutable'
import thunkMiddleware from 'redux-thunk'
import { combineReducers } from 'redux-immutable'
import { connectRouter } from 'connected-react-router'
import AppReducer from './reducers/app'
const createRootReducer = history => combineReducers({
router: connectRouter(history),
app: AppReducer
})
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(history) {
const middleware = [routerMiddleware(history), thunkMiddleware]
const rootReducer = createRootReducer(history)
return createStore(rootReducer, composeEnhancers(applyMiddleware(...middleware)))
}
appReducer
/**
* App level reducer
*/
const initialState = {
accounts: [],
employees: []
}
const reducer = (state = initialState, action) => {
switch(action.type) {
case 'ACCOUNT_SELECTION_LIST_LOADED':
return {...state, accounts: action.payload}
case 'EMPLOYEE_SELECTION_LIST_LOADED':
return {...state, employees: action.payload}
}
return state
}
export async function fetchAccountsSelectionList(dispatch, getState) {
makeAjaxRequest('/getList/accounts', 'GET', null, response => {
const accounts = JSON.parse(response)
dispatch({type: 'ACCOUNT_SELECTION_LIST_LOADED', payload: accounts})
})
}
export async function fetchEmployeesSelectionList(dispatch, getState) {
makeAjaxRequest('/getList/employees', 'GET', null, response => {
const employees = JSON.parse(response)
dispatch({type: 'EMPLOYEE_SELECTION_LIST_LOADED', payload: employees})
})
}
export default reducer
主要组件(缩小以保存 space)
import React, { Component } from 'react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import { LinkContainer } from 'react-router-bootstrap'
import { FormControl, InputGroup, Navbar, Nav, NavDropdown, NavLink } from 'react-bootstrap'
import { connect } from 'react-redux'
import { fetchAccountsSelectionList, fetchEmployeesSelectionList } from '../../store/reducers/app'
import Select from 'react-select'
class App extends Component {
constructor() {
super()
this.state = {
billId: '',
invoiceId: '',
manifestId: ''
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount() {
this.props.fetchAccountsSelectionList()
this.props.fetchEmployeesSelectionList()
}
handleChange(event) {
const {name, checked, value, type} = event.target
this.setState({[name]: type === 'checkbox' ? checked : value})
}
render() {
return (
<BrowserRouter>
<Navbar variant='dark' bg='dark' className={'navbar-expand-lg', 'navbar'}>
<LinkContainer to='/'>
<Navbar.Brand>Fast Forward Express v2.0</Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls='responsive-navbar-nav' />
<Navbar.Collapse id='responsive-navbar-nav'>
<Nav className='ml-auto'>
<NavDropdown title='Bills' id='navbar-bills'>
</NavDropdown>
<NavDropdown title='Invoices' id='navbar-invoices'>
</NavDropdown>
<NavDropdown title='Accounts' id='navbar-accounts' alignRight>
</NavDropdown>
<NavDropdown title='Employees' id='navbar-employees' alignRight>
</NavDropdown>
<LinkContainer to='/app/dispatch'><NavLink>Dispatch</NavLink></LinkContainer>
<NavDropdown title='Administration' id='navbar-admin' alignRight>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
<Switch>
<Route path='xxx' component={xxx}></Route>
</Switch>
</BrowserRouter>
)
}
}
const matchDispatchToProps = dispatch => {
return {
fetchAccountsSelectionList: () => dispatch(fetchAccountsSelectionList),
fetchEmployeesSelectionList: () => dispatch(fetchEmployeesSelectionList)
}
}
const mapStateToProps = state => {
return {
accounts: state.app.accounts,
employees: state.app.employees
}
}
export default connect(mapStateToProps, matchDispatchToProps)(App)
所以。当我注销 mapStateToProps 正在接收的“状态”时,它是一个地图,而不是一个对象,看起来像这样:
state results
为什么我的状态看起来不像我看过的任何教程?我一直无法找到任何其他这样的例子,除了一个说只是手动迭代的例子 - 但由于那不是“正确”的方式,我必须错误地配置商店
我应该注意到,开发人员工具似乎能够完美地访问状态,并反映出我期望看到的内容。为什么我无法访问 state.app.accounts
问题是您使用的两个包依赖于 Immutable.js 数据结构,而不是普通的 JS 对象:import { combineReducers } from 'redux-immutable'
和 import { routerMiddleware } from 'connected-react-router/immutable'。
特别是,来自 redux-immutable
的 combineReducers
将导致根状态对象成为 Immutable.js Map
实例,而不是普通对象,并且Map
实例有 .get()
和 .set()
方法而不是普通字段。
We strongly recommend against using Immutable.js in Redux apps at this point.
相反,您应该将您的状态写成纯 JS 对象和数组,并且您应该使用 our official Redux Toolkit package 来设置您的商店并编写您的缩减程序。
请阅读 Redux 核心文档中的官方 "Redux Essentials" and "Redux Fundamentals" 教程,了解如何使用 Redux Toolkit 编写 Redux 逻辑。