0

在 mapStateToProps 中,它应该像访问所需状态部分的密钥一样简单,并获取 state 参数,但我无法这样做。

主 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)))
}

应用减速器

/**
 * 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

主要组件(缩小以节省空间)

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 正在接收的“状态”时,它是一个 Map,而不是一个对象,看起来像这样:

状态结果

为什么我的状态看起来不像我看过的任何教程?我一直找不到像这样的任何其他示例,除了一个说只是手动迭代的示例 - 但由于这不是“正确”的方式,我必须错误地配置存储

我应该注意到,开发人员工具似乎能够完美地访问状态,并反映我期望看到的内容。为什么我无法访问 state.app.accounts

4

1 回答 1

1

问题是你使用了两个依赖于 Immutable.js 数据结构的包,而不是普通的 JS 对象:import { combineReducers } from 'redux-immutable'并 import { routerMiddleware } from 'connected-react-router/immutable'。

特别是,该combineReducersfromredux-immutable将导致根状态对象成为 Immutable.jsMap实例,而不是普通对象,并且该Map实例具有.get().set()方法而不是普通字段。

我们强烈建议此时不要在 Redux 应用程序中使用 Immutable.js

相反,你应该将你的状态写成普通的 JS 对象和数组,并且你应该使用我们的官方 Redux Toolkit 包来设置你的 store 并编写你的 reducer。

请阅读 Redux 核心文档中的官方“Redux Essentials”“Redux Fundamentals”教程,了解如何使用 Redux Toolkit 编写 Redux 逻辑。

于 2020-11-25T18:16:05.970 回答