import { createStore } from 'redux'; const initialState = { auth: { loggedIn: false } } const store = createStore((state = initialState, action) => { switch (action.type) { case "LOG_IN": return { ...state, auth: { loggedIn: true } }; break; case "LOG_OUT": return { ...state, auth: { loggedIn: false } }; break; default: return state; break; } })
<Provider store>
- allows you to create a wrapper for a React application and make Redux state accessible to all container components in its hierarchy.connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
- allows you to create higher-order components. This is needed to create container components based on React base components. npm install react-redux --save
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import createStore from './createReduxStore'; const store = createStore(); const rootElement = document.getElementById('root'); ReactDOM.render(( <Provider store={store}> <AppRootComponent /> </Provider> ), rootElement);
AppRootComponent
hierarchy using the connect()
API.connect()
API is used to create container components that are connected to the Redux repository. The storage to which the connection is made is obtained from the uppermost ancestor of the component using the React context mechanism. You will not need the connect()
function if you only create presentation components.connect()
function from react-redux. Here's what it looks like: import React from 'react'; import { connect } from 'react-redux'; import Profile from './components/Profile'; function ProfileContainer(props) { return ( props.loggedIn ? <Profile profile={props.profile} /> : <div>Please login to view profile.</div> ) } const mapStateToProps = function(state) { return { profile: state.user.profile, loggedIn: state.auth.loggedIn } } export default connect(mapStateToProps)(ProfileContainer);
store.subscribe()
command. However, using the connect()
function means applying some performance improvements and optimizations that you may not be able to use when using other mechanisms. import React, { Component } from 'react'; import store from './reduxStore'; import Profile from './components/Profile'; class ProfileContainer extends Component { state = this.getCurrentStateFromStore() getCurrentStateFromStore() { return { profile: store.getState().user.profile, loggedIn: store.getState().auth.loggedIn } } updateStateFromStore = () => { const currentState = this.getCurrentStateFromStore(); if (this.state !== currentState) { this.setState(currentState); } } componentDidMount() { this.unsubscribeStore = store.subscribe(this.updateStateFromStore); } componentWillUnmount() { this.unsubscribeStore(); } render() { const { loggedIn, profile } = this.state; return ( loggedIn ? <Profile profile={profile} /> : <div>Please login to view profile.</div> ) } } export default ProfileContainer;
connect()
function, in addition, gives the developer additional flexibility, allowing you to customize container components to obtain dynamic properties based on the properties originally passed to them. This is very useful for getting samples from a state based on properties, or for binding action generators to a specific variable from properties.connect()
makes it easy to specify the specific repository to which the container component should be connected.connect()
function provided by the react-redux package can take up to four arguments, each of which is optional. After the call to connect()
called, a higher-order component is returned that can be used to wrap any React component. const ContainerComponent = connect()(BaseComponent);
connect()
function: connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
mapStateToProps
argument is a function that returns either a regular object or another function. Passing this connect()
argument causes the container component to subscribe to Redux storage updates. This means that the mapStateToProps
function will be called each time the state of the repository changes. If you are not interested in tracking status updates, pass connect()
as the value of this argument undefined
or null
.mapStateToProps
function mapStateToProps
declared with two parameters, the second of which is optional. The first parameter represents the current state of the Redux repository. The second parameter, if passed, is the object of the properties passed to the component: const mapStateToProps = function(state) { return { profile: state.user.profile, loggedIn: state.auth.loggedIn } } export default connect(mapStateToProps)(ProfileComponent);
mapStateToProps
, then the returned stateProps
object stateProps
combined with the properties of the component. You can access these properties in a component like this: function ProfileComponent(props) { return ( props.loggedIn ? <Profile profile={props.profile} /> : <div>Please login to view profile.</div> ) }
mapStateToProps
returns a function, then this function is used as mapStateToProps
for each component instance. This can be useful for improving rendering performance and for memoization.mapDispatchToProps
argument can be either an object, or a function that returns either a regular object or another function. In order to better illustrate the work of mapDispatchToProps
, we will need action generators. Suppose we have the following generators: export const writeComment = (comment) => ({ comment, type: 'WRITE_COMMENT' }); export const updateComment = (id, comment) => ({ id, comment, type: 'UPDATE_COMMENT' }); export const deleteComment = (id) => ({ id, type: 'DELETE_COMMENT' });
mapDispatchToProps
.mapDispatchToProps
, represented by an object or function, the standard implementation will be used, using which you implement the dispatch()
storage method as a property for the component. You can use this property in the component as follows: import React from 'react'; import { connect } from 'react-redux'; import { updateComment, deleteComment } from './actions'; function Comment(props) { const { id, content } = props.comment; // props.dispatch() const editComment = () => props.dispatch(updateComment(id, content)); const removeComment = () => props.dispatch(deleteComment(id)); return ( <div> <p>{ content }</p> <button type="button" onClick={editComment}>Edit Comment</button> <button type="button" onClick={removeComment}>Remove Comment</button> </div> ) } export default connect()(Comment);
mapDispatchToProps
, then each function in the object will be interpreted as a Redux action generator and wrapped in a call to the dispatch()
repository method, which will allow it to be called directly. The resulting object with the action generators, dispatchProps
, will be merged with the properties of the component.mapDispatchToProps
argument, which is an object with action generators, and how the generators can be used as properties of the React component: import React from 'react'; import { connect } from 'react-redux'; import { updateComment, deleteComment } from './actions'; function Comment(props) { const { id, content } = props.comment; // , , const editComment = () => props.updatePostComment(id, content); const removeComment = () => props.deletePostComment(id); return ( <div> <p>{ content }</p> <button type="button" onClick={editComment}>Edit Comment</button> <button type="button" onClick={removeComment}>Remove Comment</button> </div> ) } // const mapDispatchToProps = { updatePostComment: updateComment, deletePostComment: deleteComment } export default connect(null, mapDispatchToProps)(Comment);
mapDispatchToProps
as an argument mapDispatchToProps
the programmer must take care of returning the dispatchProps
object, which binds the action generators using the dispatch()
method of the repository. This function takes, as the first parameter, the dispatch()
storage method. As in the case with mapStateToProps
, the function can also take the optional second parameter ownProps
, which describes the mapping with the original properties passed to the component.mapDispatchToProps
, which can be useful for the purposes of improving rendering performance and memoization.bindActionCreators()
helper function can be used inside this function to bind action generators to the dispatch()
repository method.mapDispatchToProps
role. It also demonstrates bindActionCreators()
work with the bindActionCreators()
helper function used to bind action generators to work with comments to props.actions
of the React component: import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import * as commentActions from './actions'; function Comment(props) { const { id, content } = props.comment; const { updateComment, deleteComment } = props.actions; // props.actions const editComment = () => updateComment(id, content); const removeComment = () => deleteComment(id); return ( <div> <p>{ content }</p> <button type="button" onClick={editComment}>Edit Comment</button> <button type="button" onClick={removeComment}>Remove Comment</button> </div> ) } const mapDispatchToProps = (dispatch) => { return { actions: bindActionCreators(commentActions, dispatch) } } export default connect(null, mapDispatchToProps)(Comment);
connect()
function is given the argument mergeProps
, then it is a function that takes the following three parameters:stateProps
is the property object returned from the mapStateToProps()
call.dispatchProps
is a property object with action generators from mapDispatchToProps()
.ownProps
- the initial properties received by the component.connect()
does not pass this function, then its standard implementation is used: const mergeProps = (stateProps, dispatchProps, ownProps) => { return Object.assign({}, ownProps, stateProps, dispatchProps) }
connect()
as the fourth argument contains parameters intended to change the behavior of this function. So, connect()
is a special implementation of the connectAdvanced()
function, it accepts most of the parameters available to connectAdvanced()
, as well as some additional parameters.connect()
and how they modify the behavior of this function.connect()
, you need to create a Redux repository to which this component will be connected.NewComment
, which is used to add new comments to a publication, and, in addition, displays a button to send a comment. The code describing this component might look like this: import React from 'react'; import { connect } from 'react-redux'; class NewComment extends React.Component { input = null writeComment = evt => { evt.preventDefault(); const comment = this.input.value; comment && this.props.dispatch({ type: 'WRITE_COMMENT', comment }); } render() { const { id, content } = this.props.comment; return ( <div> <input type="text" ref={e => this.input = e} placeholder="Write a comment" /> <button type="button" onClick={this.writeComment}>Submit Comment</button> </div> ) } } export default connect()(NewComment);
store
property: import React from 'react'; import store from './reduxStore'; import NewComment from './components/NewComment'; function CommentsApp(props) { return <NewComment store={store} /> }
<Provider>
component that can be used to wrap the root component of an application. It takes the property store
. It is assumed that it is a link to the Redux repository that is planned to be used in the application. The store
property is passed, in accordance with the application hierarchy, to the container components using the React context mechanism: import React from 'react'; import ReactDOM from 'react-dom'; import store from './reduxStore'; import { Provider } from 'react-redux'; import NewComment from './components/NewComment'; function CommentsApp(props) { return <NewComment /> } ReactDOM.render(( <Provider store={store}> <CommentsApp /> </Provider> ), document.getElementById('root'))
mapStateToProps
and mapDispatchToProps
functions mapStateToProps
to connect()
can be declared with the second parameter ownProps
, which is the properties of the component.ownProps
will not be transmitted. But if the function is declared with the absence of required parameters or, at least, with 2 parameters, its ownProps
will be transferred.ownProps
. const mapStateToProps = function() { console.log(arguments[0]); // state console.log(arguments[1]); // ownProps };
ownProps
passed, because the function is declared without the required parameters. As a result, the following code written using the new syntax of the remaining ES6 parameters will work: const mapStateToProps = function(...args) { console.log(args[0]); // state console.log(args[1]); // ownProps };
const mapStateToProps = function(state) { console.log(state); // state console.log(arguments[1]); // undefined };
state
. As a result, arguments[1]
is set to undefined
because ownProps
not passed. const mapStateToProps = function(state, ownProps = {}) { console.log(state); // state console.log(ownProps); // {} };
state
, since the second parameter, ownProps
, is optional due to the default value for it. As a result, since there is only one mandatory parameter, ownProps
not passed, and mapping is performed with the default value that was assigned to it, that is, with an empty object. const mapStateToProps = function(state, ownProps) { console.log(state); // state console.log(ownProps); // ownProps };
ownProps
transferred because the function is declared with two mandatory parameters.connect()
API provided by the react-redux package and designed to create container components that are connected to the Redux state. Here we talked in some detail about the device's connect()
function and how to work with it, however, if you want to learn more about this mechanism, in particular, to familiarize yourself with the options for using it, take a look at this section of the react-redux documentation.Source: https://habr.com/ru/post/423157/
All Articles