Reputation: 712
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.
Upvotes: 14
Views: 15231
Reputation: 404
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:
App calls TodoList with
<TodoList todos={visibleTodos} onTodoClick={ index => dispatch(completeTodo(index)) } />
TodoList calls Todo with
<Todo {...todo} key={index} onClick={ () => this.props.onTodoClick(index) } />
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.
Upvotes: 7
Reputation: 12780
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 };
}
}
Upvotes: 16
Reputation: 6209
Two options:
Pass a bound actionCreator from your Container (which is connected to Redux) down to a child component (which is not connected to Redux) via the props
object.
Consider adopting React Component Context in your project.
Upvotes: 1