When we connect Container component with Redux Store and write mapStateToProps in Container Component.
const mapStateToProps = (state) => {
//Access state here
};
Does the state which mapStateToProps receives is complete Store state or some part of store state which only that Container component needed?
Does every Container Component receives Complete Store State?
Redux has a strong set of principles as The store is the single source of truth, So yes when you connect a component to the Redux store using mapStateToProps, you have access to the complete state object but it is you who decides what part of the state the component needs.
For example, you have an inventory reducer and a cart reducer in your store which both have an array of items as state value. In mapStatetoProps you have access to both the reducers' states, but you decide what your component needs. You can connect to state.cart.items or state.inventory.items or both if you want to.
const mapStateToProps = (state) => ({
// it is you who decides what your component need from the store in order to function
// you can only select state.cart.items or state.inventory.items or both if you need
cartItems: state.cart.items,
inventoryItems: state.inventory.items
});
"store" you passed in store parameter in provider will be made availabe for your App Component and its child component.
<Provider store={store}>
<App />
</Provider>
Since we passed whole store to our Provider,whole state is automatically passed to all child components of App Component.
To setup different provider with differet store,you can follow this
How to set up multiple providers with different stores?
mapStateToProps is a method of react-redux library and it connects react components with redux store. when data is loaded root reducer combines state of all reducers and returns to mapStateToProps(state) object so yes mapStateToProps get complete redux store state.
Related
I have a component which need logged-in user data but in this component I'm not sure if user is logged in yet or not
is it a bad practice to check existance data in mapStateToProps and redirect to login page if needed? is it a side effect?
what about fetching data which is nit exist in state yet?
how should I handle such problems?
what should we do in mapState and what we shouldn't do?
is there any good practice for it?
it a bad practice to check existance data in mapStateToProps and redirect to login page if needed?
I am not sure of whether it's a best practice or not, but if we look at the semantics of mapStateToProps, it's main usage is mapping redux state to component props.
So in that sense anything that is not mapping can be considered a side-effect.
If you want to align with redux-way then you pass down with mapStateToProps properties that you want to react to, and you change those properties with mapDispatchToProps.
So in your case you would have some sort of Authentication service, that would have methods like login, logout, register, which would dispatch actions to your redux store, and in mapStateToProps you would subscribe to something like isAuthenticated.
And in your render you would check if this.props.isAuthenticated ? <PrintSome> : null
You can also check this tutorial with basically same idea, but taken out into a higher order component for reusability https://medium.com/quick-code/adding-authentication-to-react-redux-firebase-app-f0efcb1c519a
So let's assume you have defined your routes in the src/components/App.js component. You are at a point where you need to ensure that your App component knows whether or not the user is actually signed in at all.
Let's also assume that you have already developed a reducer in reducers/auth.js to record whether a user is signed in or not and you have assigned the authReducer to your auth piece of state.
At this point, inside your src/components/App.js file you would need to import:
import { connect } from 'react-redux';
Then at the bottom of your App component you need to define your mapStateToProps like so:
function mapStateToProps(state) {
return { auth: state.auth }
}
export default App;
So what I am recommending above is that you pass state to mapStateToProps and then return an object with a key of auth and that will take whatever value is coming out of the authReducer.
Then you take the connect() function you imported and pass mapStateToProps to it like so:
export default connect(mapStateToProps)(App);
So now your App component knows whether or not the user is signed in.
So what is an advantage of implementing the above? Well, it gives you the flexibility of determining what to display in your view depending on whether the user is signed in or not. For example, a sign-in/sign-out button.
You can now develop that button with a helper method that has a conditional like so:
renderButton() {
if (this.props.auth) {
return (
<button>
Sign Out
</button>
);
} else {
return (
<button>
Sign In
</button>
);
}
}
I just start learning how redux work :
What redux mean by there is one particular function take the whole state of the application and action is been dispatched and return the whole new state of the application?
is this is visible on Enterprise level application Single Page Application ERP system or I have misunderstood something?
also how the function be pure and change in the previous state " use ref of the previous state and add to it new data then return this as an object?
if it is not is that will not affect the speed of the system to copy each time the whole system state for ERP system?
the course in which I get this info 1
the course in which I get this info 2
Redux in general
In redux, your app's state is represented as a single object which is passed to your app.
This single object is constructed by a single function which is called reducer. This function takes the current state and current action as arguments and returns a new object which represents the new state changed after the action is reduced.
It's kinda similar to Array.prototype.reduce where you get current accumulator (current state) current array entry (current action) and return new accumulator (new state) depending on what is the current accumulator and entry (state and action).
Combining reducers
Nevertheless, this doesn't mean you need to put all of your app's logic in one function. Redux has a helper combineReducers to let you write reducers for different parts of your state and then combine them into single reducer that constructs a single state object.
For example for a blog app with posts and comments, you can use it like that:
import { combineReducers, createStore } from 'redux';
import postsReducer from './postReducer';
import commentsReducer from './commentsReducer';
const rootReducer = combineReducers({
posts: postsReducer,
comments: commentsReducer,
});
const store = createStore(rootReducer);
Where postReducer and commentsReducer are two separate reducers each handling their part of the state.
I am working on a React/Redux application. Let's say I have a component that receives two props from it's container:
// NewsFeedItem.js
class NewsFeedItem extends React.Component {
render() {
const user = this.props.user;
const item = this.props.item;
return <p>{user.name} - {item.date}</p>;
}
}
const mapStateToProps = (state) => ({
user: state.user,
item: state.user.items[0],
});
export default connect(mapStateToProps)(NewsFeedItem);
How can I make sure this Component doesn't update if I make a change to the 2nd or 3rd item in the items list?
Pasting in my answer from the associated Redux issue for completeness:
First, there's nothing wrong with a React component re-rendering - that's how React works in the first place. If a component re-renders with the same data and produces the same render output, then React just doesn't update the DOM. Now, sure, that's considered a "wasted" re-render that probably could have been avoided, but it's only a problem if you're trying to seriously optimize performance.
Second: yes, if you're correctly immutably updating your state, then an update to state.user.items[3] should result in new references for items, user, and state, and passing user as a prop to the component like that would cause it to re-render. However, in your specific example, that component is only using user.name. so there's no reason to pass the entire user object as a prop - try passing just name : state.user.name instead.
Third, you could split up the storage of the user attributes and their associated items into separate parts of the state, so that an update to an item doesn't cause an update to the associated user object. See the Normalizing State Shape page in the Redux docs as an example.
Finally, you could always implement a custom shouldComponentUpdate in your component, and do an additional check there to see if the component should skip re-rendering.
I am trying to update the reducer state using :
store.dispatch(NameOftheReducer(data)).
It calls the Action creator but it does not update the reducer state. I dont want to create any React component from where i want to dispatch the state change. Is there any way to do so..Thanks in advance
Lets assume the store is stored stored somewhere global
then you can just
store.dispatch({
type: "SOME_ACTION",
value: "value"
})
if you have some actionCreator like:
function someAction(value) {
return {
type: "SOME_ACTION",
value: value
}
}
And and now you can use it with dispatch:
store.dispatch(someAction("some value"))
Did I missed something?
I think you misunderstood how component and redux state relates.
redux state change are done through actions regardless of which component is actually 'using' this state.
As long as you have an action creator defined somewhere, and you reducer handle the corresponding action.type, then you can use this action creator in whichever component.
There is no benefit of using store directly. store is stored in context, and it is generally considered bad practice using context. The nice thing about redux is that it takes care of this by giving you Provider and connect.
Except when initializing the app, you should always use mapDispatchToProps when you want to use action creators in your component.
All:
When I read the source of Redux, in its createStore:
function createStore(reducer, initialState, enhancer) {
......
var currentState = initialState;
......
dispatch({ type: ActionTypes.INIT });
......
}
When create a new store, it sets currentState to initialState, and call reducer in init dispatch to update the default state value. I wonder: generally the currentStatew will be given a value from reducer, then what is the purpose of that initialState?
Thanks
Normally, just specify the initial state as reducer default argument, and let each reducer manage it for themselves.
However in some cases you want to “hydrate” the state with existing data. For example, you might have saved the whole state tree in a localStorage and want to load it from there on startup, or maybe you are rendering on the server, and want to load the initial state you saved on the server from the HTML.
In this case, the initialState to createStore() is useful because it lets you optionally hydrate some parts of the tree where you have pre-populated data. In this case, it would “win” to the reducer default state which is usually the behavior you would want. The parts of the state tree that exist in initialState would be used as is, and the missing parts would be retrieved from the reducers. This makes it possible to “restore” some parts of the state, but always re-initialize the others.
Hopefully this answer should provide a more in-depth explanation of this technique.