Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dispatch actions from Child components three level down?

I am currently facing this issue designing a React application and I don't seem to be able to find an answer to it.

So my application has following heirarchy of Components in React Router

App -> DynamicContainer -> -> LoginComponent

Now, LoginComponents has form elements to take username and password.

I have userActionCreators where the login is handled, and it dispatches login successful when finished, but I don't seem to be able find the right way to connect my LoginComponent to dispatch actions or call actionCreators.

How do I do it? Any suggestion would be appreciated.

like image 520
Nitesh Avatar asked Oct 20 '15 18:10

Nitesh


People also ask

Should I pass dispatch as prop?

Pass the dispatch function as propsPassing the dispatch function from containers to child function can solve the problem of making each of our child components as smart components.

How do you pass data between child components?

First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.

What happens when you try to dispatch an action within a reducer?

Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions and other side effects.


2 Answers

One option is to bind your single-purpose forms to their actions with connect. Since <LoginComponent /> is typically always doing the exact same thing, you can use it like this:

import React from 'react';
import * as userActionCreators from '../actions/users';
import { connect } from 'react-redux';

export class LoginComponent extends React.Component {
   static propTypes = {
     login: React.PropTypes.func.isRequired
   }

   render() { 
     const { login } = this.props;
     const { username, password } = this.state;

     return (
       <form onSubmit={ () => login(username, password) }>
         ...
       </form>
     );
   }
}

export default connect(null, userActionCreators)(LoginComponent);

connect automatically binds the action creator and separately provides dispatch to props, so if you want to be more explicit, the above example is the same as

import React from 'react';
import { login } from '../actions/users';
import { connect } from 'react-redux';

export class LoginComponent extends React.Component {
   static propTypes = {
     dispatch: React.PropTypes.func.isRequired
   }

   render() { 
     const { login, dispatch } = this.props;
     const { username, password } = this.state;

     return (
       <form onSubmit={ () => dispatch(login(username, password)) }>
         ...
       </form>
     );
   }
}

export default connect()(LoginComponent);

And for reference, userActionCreators:

const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
const LOGIN_FAILED = 'LOGIN_FAILED';

export function login(username, password) {
  if (username === 'realUser' && password === 'secretPassword') {
    return { type: LOGIN_SUCCESS, payload: { name: 'Joe', username: 'realUser' } };
  } else {
    return { type: LOGIN_FAILED, error: 'Invalid username or password };
  }
}
like image 135
Nathan Hagen Avatar answered Sep 22 '22 12:09

Nathan Hagen


if I understood you correctly, if you read Example: Todo List | Redux you'll find the example that you might be looking for.

There's the App component, connect()ed to Redux, and then there're the other components: AddTodo, TodoList, Todo and Footer.

App calls TodoList that calls Todo where user can click something. This click will surf back callback after callback, from Todo to TodoList to App as detailed below:

  1. App calls TodoList with <TodoList todos={visibleTodos} onTodoClick={ index => dispatch(completeTodo(index)) } />

  2. TodoList calls Todo with <Todo {...todo} key={index} onClick={ () => this.props.onTodoClick(index) } />

  3. Todo component has a <li> with onClick={this.props.onClick} property.

So, backwards, when someones clicks inside the Todo compoment, that will call this.props.onClick which will call this.props.onTodoClick(index) from TodoList (notice the optional added parameter index), then, at last, this will invoke the function dispatch(completeTodo(index)) from App.

like image 41
Henrique Pantarotto Avatar answered Sep 23 '22 12:09

Henrique Pantarotto