Why redux create state in store with '0' name? - javascript

I use React, Redux and Redux-saga. For reducers I use combineReducers(). In the reducer I set initial state like this:
const authentication = (state = [{isAuthenticated: false}], action) =>
{
switch (action.type) {
case USER_LOGIN_TRY:
return Object.assign({}, state, userLogin(action.email))
default:
return state;
}
}
This creates the authentication object with the variable isAuthenticated. However, when I retrieve this value from state, after the initial state is set, I see in Redux DevTools (and in the console) that redux created the field with name '0' and my initial state.
Why does Redux creates this field? Can I disable this? I don't want to create several code blocks for inspecting field with '0' prefix in my code.

doing state = [{isAuthenticated: false}] makes your default an array

Related

Two ways of updating an array in redux state object, why does one work and the other doesn't?

I initially had my reducer as such, and it does not work (my updated redux state does not lead my component to update, my component's prop 'RecipeStore' is mapped onto the redux state's 'myRecipes' property)
const initialState={
myRecipes: []
}
export default function(state=initialState, action){
switch(action.type){
case SUBMIT_RECIPE:
const newState={...state}
newState.myRecipes.push(action.payload)
return newState
default:
return state;}}
I figured that my component did not rerender with redux store update because I mutated state, and you should never mutate state. So I rewrote the reducer as such:
const initialState={
myRecipes: []
}
export default function(state=initialState, action){
switch(action.type){
case SUBMIT_RECIPE:
console.log("reducer invoked")
const copyState={...state, myRecipes:state.myRecipes.concat(action.payload)}
return copyState
default:
return state;
}
}
And this time it worked - my component updates every time the redux store changes. However - my original reducer also created a copy of the original state using the spread operator, and only mutated the copy, why doesn't it work?
This is one of these situations where I'm glad that I solved the problem but am peeved that I don't know why.
Can someone lend me their thought?

Why do we need to return state from reducer in Redux?

I am new to Redux and was trying to get how to work with Redux properly but I encountered a confusion on why we need to return state in reducer. Here is the code:
const initialState = {
counter: 0
};
const reducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return {
counter: state.counter + 1
};
}
return state; // why do we need to use this code?
};
export default reducer;
Basically the reducer gets the previous state of your predefined object as an argument and the function must return in every single case the new state of the object.
In the Redux reducers documentation you can see the following statement:
The reducer is a pure function that takes the previous state and an action, and returns the next state.
Read further about Handling actions in Redux.
If you see the docs,
Reducers specify how the application's state changes in response to actions sent to the store. Remember that actions only describe what happened, but don't describe how the application's state changes.
So whenever you call an action, reducer must return a new state based on that action.
In your case, (action.type === "INCREMENT) if action.type doesn't match your cases and you haven't set any default case it will return null value.
Now your redux state will have no mention about your given state if you won't return any value that's why default state is needed to maintain state data in reducer store.

Different ways of initializing a react redux store's initial global state?

What are the different ways of initializing a react redux store's initial global state? I see two ways this redux could set an initial global state
Let's say we have a single reducer and all the javascript is in one file.
function rootReducer(state = "Initial Reducer State!", action){
switch(action.type) {
case SET_TEXT:
return "Ignore this case statement it won't run"
default:
return state;
}
}
(1) I know you can use something like createStore(rootReducer, initialState).
const store = createStore(
rootReducer,
initialState
)
const initialState = {
text: "Initial Global State!"
}
(2) However, I noticed some repos setting an initialState to a blank object, but the redux store shows a global state has been populated. Example from this stackoverflow post: how to set initial state in redux
const store = createStore(
combineReducers({
text: rootReducer
}),
initialState
)
const initialState ={}
Resulting global store:
(1) outputs {text: "Initial Global State!"}
(2) outputs {text: "Initial Reducer State!"}
Why does #2 work the way it does?
When and where does it get set?
[answer comes from me playing around with redux and getting advice from a senior react-redux dev, Andrew Dushane]
When a store is created through redux, every reducer automatically gets triggered one time
There's an action dispatched when the store is created. That's how the initial state supplied in each combined reducer gets initialized in the store. If you check redux dev tools you'll see the first action dispatched is "##redux/INIT{something}"
In redux's documentation, near the end of the file, there is a dispatch({ type: ActionTypes.INIT })
See here https://github.com/reduxjs/redux/blob/master/src/createStore.js#L281-L284
TLDR
Because in example #2,
store is created
combineReducers({text: rootReducer}) gets set
rootReducer runs, because every reducer runs one time on store creation
Default return value is made, in this case "Initial Reducer state!"
text in ({text: rootReducer}) captures response
{text: "Initial Reducer State!"} gets stored as global state
Final Notes
if you were to set an initialState on the store, this always runs after all the reducers get dispatched one time.

Why is the reducer seemingly called by default in Redux?

I am running a simple Redux reducer and store, but for some reason the reducer is called by default. Is that normal?
const apiWrapper = (state = {}, action) => {
switch(action.type) {
case "HELLO":
console.log("hello");
return state;
break;
default:
console.log("default");
}
}
const { createStore } = Redux;
const store = createStore(apiWrapper);
store.dispatch({ type: "HELLO" });
The snippet above outputs:
"default"
"hello"
I am only expecting it to log hello, why is default there too? Here's a JSBin.
Redux internally dispatches a dummy action when creating the store in order to set up the initial state. Per the Redux documentation:
When a store is created, Redux dispatches a dummy action to your reducer to populate the store with the initial state. You are not meant to handle the dummy action directly. Just remember that your reducer should return some kind of initial state if the state given to it as the first argument is undefined, and you're all set.
So when your reducer is first called, state will be undefined thus your default value {} will be used. Also, it will go to the default case because you're not supposed to explicitly handle the action, and thus you get the console.log. Make sure to return the state in the default case to set up initial state correctly.
Just out of curiosity, the action type the first dummy call Redux does is "##redux/INIT" signifying that Redux is initializing the store and testing it. A similar thing happens with combineReducers to test for bad patterns in reducers. Specifically, in the source:
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT })
So the initial dispatch essentially gives each reducer its respective slice of state, and populates the initial state tree.

Redux mapStateToProps returns undefined

Redux is successfully storing and updating state. The reducers are seemingly working correctly. I'm able to use this.props.dispatch. However, when it actually comes to detailing that information (i.e. this.props.array I always seem to get undefined.
Reducer:
export default function array(state = {}, action) {
switch (action.type) {
case "UPDATE_ARRAY":
state.array = action.array
return state;
default:
return state;
}
}
State-aware component:
constructor(props) {
super(props);
this.state = {
array: array
}
}
--
self.props.dispatch({
type: 'UPDATE_ARRAY',
array: array
})
--
const mapStateToProps = (state) => {
return {
messages: state.messages,
array: state.array
};
};
export default connect(mapStateToProps)(Component);
This only seems to be able to save state btw when I define an empty array. This doesn't seem right, I thought the intention of Redux was a self-contained store? Updating a variable seems to defeat the purpose a bit.
Would appreciate any help.
export default function array(state = {}, action) {
switch (action.type) {
case "UPDATE_ARRAY":state={
...state,
array:action.array
}
return state;
default:
return state;
}
}
you should always update your state immutably,instead of mutating the current application state ,you should create another object and return that.State should be immutable ,only way to change the state is to create a new one.This helps to improve the performance of the application.
I am not sure if you application has more than one reducer or not, if it has, than you must be using combine reducer method .So to access state.array in mapsStateToProps is like this
const mapStateToProps = (state) => {
return {
messages: state.{reducer_name}.message,
array: state.{reducer_name}.array
};
};
in place of 'reducer_name' you have to specify the reducers_name which you have define in combine reducer
And last mapStateToProps return array ,in props not in component state.
which you can access in this way {this.props.array},you cant set component state in componentDidMount and in componentWillRecieveProps (in case of aysnc action).
Your component will receive array as a field in its props field. Your code assumes it's in the state field. So instead of:
this.state = {
array: array
}
you would just access this.props.array wherever in your code you need to use the array. You don't need to put it in the local state at all. Usually, you would use it in the render function, like in this example:
render()
{
return <div>The array contains {this.props.array.length} items.</div>
}
I wonder if you're confusing local state with the Redux store's state? Local state is what you get/set when you access this.state in your component code. Every component can have its own state object that it can read from and write to.
The Redux store's state is what's passed in to mapStateToProps. It's usually the entire state object of all the combined reducers in your top-level reducer (though if you only have one reducer function and are not using combineReducers, then the store state is identical to that single reducer's state).
I suggest choosing more descriptive variable names, so that your code will be more readable. It's hard to understand what your intentions are for your code with such generic names. For example, you could name your reducer something that indicates what it's for, like bookListReducer, and name the array you want to store and retrieve for what will go inside it, like books. Naming both your reducer and all your variables array makes it harder to read your code. This will help anyone who reads your code in the future - including, most importantly, you!, as well as future Stack Overflow readers of your future questions (and perhaps this one if you edit it).
I am not sure the following is your issues, but hope these will help:
export default function array(state = {}, {type, array}) {
switch (type) {
case "UPDATE_ARRAY":
return {...state, array};
default:
return state;
}
}
Your reducer should be pure, which you had is mutating the state.
constructor(props) {
super(props);
this.state = {
array: array // what is array?
}
}
Above constructor is not right. You should be able to access the array from this.props.array as your mapStateToProps
Do a console.log(this.props) in your render function or ComponentWillReceiveProps, see if you can something :)

Categories

Resources