8
votes

I use redux + react to build my website, and I want to use redux to control a sidebar visible.The sidebar is defined by semantic-ui-react.Because I want to control it across another component, so I defined the props in sidebar's parent component const { visible, dispatch } = this.props, there is a onClick function to handle this. I will show my code.

Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

This error confused me one afternoon, and I don't know why! This is my action code:

**action**

export const SIDEBARISVISIBLE = 'sidebarVisible'

export function sidebarVisibleAction() {
  return { type: SIDEBARISVISIBLE }
}

As you can see, I defined an action creator returned a plain object.

And this is my reducer code:

**reducer**

import SIDEBARISVISIBLE from '../actions/outside.js'

function sidebarVisible(state = {
  sidebarIsVisible: false
}, action) {

    switch (action.type) {
        case SIDEBARISVISIBLE:
            return Object.assign({}, state, {
                sidebarIsVisible: !state.sidebarIsVisible
            })
        default:
            return state
    }
}

export default sidebarVisible

Also my store code:

**store**

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import sidebarVisible from '../reducers/outside.js'

export default initialState => {
  return createStore(
    sidebarVisible,
    initialState,
    applyMiddleware(thunk)
  )
}

Then, my component code(part of):

class OutsideView extends Component {

    constructor(props) {
        super(props)
        this.state = { activeItem: '' }
    }

    handleItemClick = (e, { name }) => this.setState({ activeItem: name })

    render() {
        const { activeItem } = this.state
        const { visible, dispatch } = this.props

        return (
            <div>
                <SidebarNav visible={ visible } />

                ......

                   <Menu.Item
                    name='sidebar'
                    active={ activeItem === 'sidebar'}
                    onClick={ (e, {name}) => {
                                this.setState({ activeItem: name })
                                dispatch(sidebarVisibleAction)
                            } }>
                    <Icon color='red' name='list' />
                </Menu.Item>

OutsideView.PropTypes = {
    visible: PropTypes.bool.isRequired,
    dispatch: PropTypes.func.isRequired
}

function mapStateToProps(state) {
  return {
    visible: state.sidebarIsVisible,
  }
}

export default connect(
    mapStateToProps
)(OutsideView)

The last, my Router:

import configureStore from './store/index.js'
const store = configureStore()

export default class Root extends Component {

    render() {
        return (
            <Provider store={ store }>
            <Router history={ browserHistory }>
                <Route path="/" component={ OutsideRedux }>
                    <Route path='register' component={ Register } />
                    <Route path='login' component={ Login } />
                    <Route path='blog' component={ Blog } />
                    <Route path='about' component={ About } />
                    <Route path='home' component={ Home } />
                    <Route path='ask' component={ Ask } />
                    <Route path='panel' component={ Panel } />
                    <Route path='setting' component={ Setting } />
                    <Route path='user' component={ User } />
                </Route>
            </Router>
            </Provider>
        )
    }
}

So, I search for answer for this error, most of them say, you have to setup redux-thunk and with ApplyMiddleware to use it, the simplest way.But the action I defined is plain object.If I don't use redux-thunk, I think I will not encounter this error either.So, I'm very confused, how to solve this?

Thanks for all the help

1
Not sure that's related, therefore I'm writing this as a comment. Why are you using dispatch? You should use mapDispatchToProps in connect and get the action as this.props.actionName. Just make sure you use the props version and not the imported one. Made this mistake too many times :DMarko Gresak
Also a general comment about your code, why use component state if you're already using redux? If you're using redux, it's best to do all all state management via redux, the code is easier to reason about and more simple to test. An extra bonus is that this way, you don't need class, you can use pure component.Marko Gresak
@MarkoGrešak Yes, I will explain about you said.First, I use dispatch, because I refer to the official redux Reddit API code.Second, the state I use is just for active an item, this is semantic-ui-react default achieve, so I am not change it.g1eny0ung
Except some very basic examples, I haven't used dispatch in my code, therefore I failed to see the error, but @nobody found the answer. But what I suggested would still work, because mapDispatchToProps warps the action as dispatch call, so you can use the action as regular function and omit the dispatch(action(args)) syntax in favor of, in my opinion, more clean action(args) call.Marko Gresak

1 Answers

27
votes

Here:

dispatch(sidebarVisibleAction)

you are passing function sidebarVisibleAction to dispach. You should call it and pass result, so the code will look like:

dispatch(sidebarVisibleAction())

(now dispatch will get object, not a function).