In the react-redux documentation it states that when using React-redux and connect()
importing the store is not recommended. It's an anti-pattern.
http://redux.js.org/docs/faq/StoreSetup.html
Similarly, while you can reference your store instance by importing it directly, this is not a recommended pattern in Redux. If you create a store instance and export it from a module, it will become a singleton. This means it will be harder to isolate a Redux app as a component of a larger app, if this is ever necessary, or to enable server rendering, because on the server you want to create separate store instances for every request.
With React Redux, the wrapper classes generated by the connect() function do actually look for props.store if it exists, but it's best if you wrap your root component in and let React Redux worry about passing the store down. This way components don't need to worry about importing a store module, and isolating a Redux app or enabling server rendering is much easier to do later.
How, then, do I access the store
from any component of my choosing(even deep down in the application) once I've properly wired in the store
to my app? My code properly connects App
but I can't get access to the store from any child components at all. store.dispatch()
is null, store.getState()
is null, etc. I feel that the documentation is lacking in this regard. It's said to be magic but I'd like to know how to use the magic. Do I need to write mapDispatchToProps()
again and again for every single container component? A use case would be the currentUser
prop that would be available to every single child component in the application. I'd like to pass that down from App
to every single child.
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);//App is now a connected component, that part is working
Inside App
I have a Login
component, and I'd like to dispatch
an action
inside it. But I need a reference to store
, but apparently I'm not supposed to import
it.
This is where the concept of containers come into play.
Suppose you wanted to render a Login
component inside of your App
. You will make a connected container.
Step 1 is to create a simple action:
const LOGIN_ATTEMPT = 'auth/LOGIN_ATTEMPT';
export const login = name => ({
type: LOGIN_ATTEMPT,
payload: { name },
});
You will now use react-redux
in order to connect this action to your "presentational component". This will come through to the component as a prop
.
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { login } from 'actions/auth'; // your action
import Login from 'components/auth/Login'; // your component to connect it to.
// state refers to the "current state" of your store.
const mapStateToProps = state => ({ currentUser: state.auth.user });
// dispatch refers to `store.dispatch`
const mapDispatchToProps = dispatch => {
// calling this is like calling `store.dispatch(login(...params))`
login: bindActionCreators(login, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
This connect
function will take these two functions as parameters. You can now import this connected container and use it with the functions "bound" to it as properties.
Example component below.
export default class Login extends Component {
static propTypes = {
// properties below come from connect function above.
currentUser: PropTypes.shape({
name: PropTypes.string.isRequired,
}).isRequired,
login: PropTypes.func.isRequired,
};
state = { name: "" };
onChange = ({ target: { value: name } }) => this.setState({ name });
onSubmit = e => {
e.preventDefault();
login(this.state.name);
};
render() {
return (
<form onSubmit={this.onSubmit}>
<input
placeholder="name"
onChange={this.onChange}
value={this.state.name}
/>
</form>
);
}
}
Notice, you never had to reference the store.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With