Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass actions down to the components in redux

I want to fire an action down in my component. This is a presentation component and need not be redux aware. Router implementation is done using react-router-redux.

main.js:

let store = createStore(rootReducer)

const history = syncHistoryWithStore(hashHistory, store)

class RenderClass extends Component {
  render() {
    return (
        <Provider store={store}>
            <Router history={history}>
                <Route path="/" component={MainLayout}>
                    <Route name="employees" path="/employees" url="http://localhost:8080/" component={EmployeeTable}></Route>
                    <Route name="personalInformation" path="/personalInformation/:employeeId" url={URI} component={PersonalInformation} />
                    .....
                </Route>
            <Router>
        </Provider>
        );
    }
}   

App.jsx:

import * as Actions from './action-creator';
const MainLayout = React.createClass({
                render: function() {

                    const { dispatch, list } = this.props;
                    let actions = bindActionCreators(Actions, dispatch);
                    console.log(actions);

                    return (
                        <div className="wrapper">
                            <Header actions={actions} list={list} params={this.props.params} />

                    {React.cloneElement(this.props.children, this.props)}
                        </div>
                    )
                }
            }); 

function select(state) {
   return {
      list: state.listingReducer
   }
}
export default connect(select)(MainLayout);

header.js:

define(
    [
        'react',
        'jquery',
        'appMin'
    ],
    function (React, $) {
        var Link = require('reactRouter').Link;
        var Header = React.createClass({
            handleClick: function () {
                //Action called here
                this.props.actions.listEmployees();
            },      
            render: function () {
                return (
                    <ul className="sidebar-menu">
                        <li>
                            <Link to={'/employees'} onClick={this.handleClick}><i className="fa fa-home"></i>Employees</Link> 
                        </li> 
                    </ul>
                );
            }
        });
        return Header;
    }
)

employee.js:

define(
    [
        'react',
        'jquery',
        'appMin'
    ],
    function (React, $) {
        var EmployeeTable = React.createClass({

            render: function () {
                if (this.props.list != undefined) {
                    var listItems = this.props.list.map(function (listItem) {
                        return (
                            <tr key={listItem.id}>
                                <td> {listItem.name}</td>
                <td><Link to={'/personalInformation/' + employee.id} onClick={this.props.actions.displayPersonalInformation(employee.id)}>Personal Information</Link></td>
                                ......
                            </tr>
                        );
                    }, this);   
                    })
                }
                return (
                    <table>
                        <tbody>
                            {listItems}
                        </tbody>                    
                    </table>
                );
            }
        })  
    }
)

action-creator.js:

export function listEmployees() {
    return {
      type: types.LIST_EMPLOYEES
   };
}

export function displayPersonalInformation() {
        return {
          type: types.DISPLAY_PERSONAL_INFORMATION
       };
    }

reducer.js:
function addEmployee(state, action) {

   switch (action.type) {

      case types.LIST_EMPLOYEES:
         return {"id":"1", "name":"Stackoverflow"}

      default:
        return state
   }
}

function listingReducer(state = [], action) {
    switch (action.type) {

        case types.LIST_EMPLOYEES:
            return [
                ...state, 
                addEmployee(undefined, action)
            ]

        case types.DISPLAY_PERSONAL_INFORMATION:
                return // Gets personal Information

        default:
            return state;
    }
}


const rootReducer = combineReducers({
   listingReducer
})

export default rootReducer

The props will not contain actions since I have not tied it to props. I tried writing mapStateToProps and mapDispatchToProps in App.js as shown below:

function mapStateToProps(state) {
   return {
        list: state.list
    }
}

function mapDispatchToProps(dispatch) {
   return { actions: bindActionCreators({ actionCreators }, dispatch) }
}

export default connect(mapStateToProps, mapDispatchToProps)(MainLayout) I'm getting dispatch is not a function error. The error statement actually sounds like a duplicate question in stackoverflow, but I would also like to know the purpose why I'm using mapDispatchToProps is also right. Thanks in advance.

like image 565
User1230321 Avatar asked Nov 22 '16 04:11

User1230321


1 Answers

So from what I understand you are using export default connect(mapStateToProps, mapDispatchToProps)(MainLayout) and trying to call dispatch in MainLayout.

So from the react-redux documentation if you see you can call connect in following ways:-

  • connect()(//Component) --> dispatch would be passed as props
  • connect(mapStateToProps)(//Component) --> dispatch would be passed as props
  • connect(mapStateToProps,mapDispatchToProps)(//Component) --> dispatch would not be passed as props to your component

In scenario 3 the behavior is this way because mapDispatchToProps already has access to dispatch function. So you can bind your function to dispatch in mapDispatchToProps and then pass on this function to your component.

Example

The function you want to dispatch are dispatchMe() and dispatchMe2() which calls an action called dispatchAction. So your mapDispatchToProps would be something like :-

function mapDispatchToProps(dispatch){
  return {
     dispatchMe : () => {
       dispatch(dispatchAction()) 
    },
    dispatchMe2 : () => {
      dispatch(dispatchAction2())
    }
  }
}

Now in your component you can pass dispatchMe and call it when required.

You can read here for more info on this

like image 111
Harkirat Saluja Avatar answered Oct 10 '22 20:10

Harkirat Saluja