I was learning Redux and came across the concept of Redux selector. I got curious what that was and found out that it is a function that encapsulates the logic of slice of store state so that we can reuse it. Here is the code:
function mapStateToProps(state) {
return {
incompleteTodos: state.todos.filter((todo) => {
return !todo.completed
});
}
}
Becomes
function mapStateToProps(state) {
return {
incompleteTodos: getIncompleteTodos(state)
};
}
But the question I wanted to ask is that Is it true that when we use selector like this incompleteTodos: getIncompleteTodos(state) apart from reusability we also get memoization by default. Thus, we do not need to use reselect library. Is that true?
Short answer your question is No. By default properties in mapStateToProps is calculated every time when the component is updated, but there is some other solutions:
Reselect library which you mention, it's official package of Redux team so you can trust it.
You can use Redux Toolkit package which is also an official library and out of the box it also has Reselect.
You can use Redux Hook - useSelector which by default behaves like memorized property, so i guess this is what you are interested, in terms of default memorization.
Related
I have a side effect that detects the browser language and dispatches a browserLanguageSupported action if it is a language that my application can handle.
Now I have following reducer function that only updates the states preferredLanguage property in case it is not defined already. This is important because there are other actions that update this state property and I do not want a late browserLanguageSupported action to overwrite such a state update.
export interface State {
preferredLanguage: AppLanguage | undefined;
rehydrationComplete: boolean;
}
export const initialState: State = {
preferredLanguage: undefined,
rehydrationComplete: false
};
export const reducer = createReducer(
initialState,
on(LanguageActions.browserLanguageSupported, (state, {browserLanguage}) => {
if (!state.preferredLanguage) {
return {...state, preferredLanguage: browserLanguage};
}
return state;
})
);
Now for my question: Is it good practice to have such a condition in a reducer operator? The function itself is still pure. But I am not sure if it is good design or if I should solve it differently, lets say by adding state slice selection in the side effect that dispatches this action.
Btw. the reason I am not setting it directly in the initial state is because I get the browser language from an angular service and I am not sure if it is even possible to set initial feature state from service injection?
Best regards,
Pascal
I would to this the same way, so you get a đź‘Ť from me.
Adding a slice of the state into the effect just adds needless complexity.
The reducer contains the state, and it's OK to add logic to see if state needs to be updated or not.
Also, let's say you need to add this logic into another action/effect.
Having it in the reducer makes it easier to reuse if it's needed. Otherwise you end up with duplicate logic.
As long as the rejection (or mutation) of the data is irrelevant to the chain of actions & effects, this is absolutely valid.
However, it's worth noting that if the action in question triggers an effect which triggers an action, the triggered action will not know whether the data was rejected (or mutated) without checking the state—which is exactly what this pattern is attempting to avoid.
So, if you wanted to be able react to that rejection (or mutation), you would want to handle this in the effect. But, if you would proceed in exactly the same manner regardless of the result, then it belongs reducer.
I am still new to Vue and when I was using vue 2, I always used this:
data() {
return {
....
}
}
methods: {
....
}
but now I see a lot of docs with
setup() {
const .....
return { ... }
}
are these essentially the same? when would be a use case for data() vs setup()?
In Vue.js 2 you have been using the so-called Options API. Vue.js 3 comes with the Composition API that can be used instead of the Options API.
Both ways are essentially the same and you can go with either one. However, you should understand the difference (for example, this doesn't refer to the component in the setup() method and you shouldn't use it).
The Composition API approach is better for various reasons explained in detail in the official FAQ. In short, it provides:
Better Logic Reuse
More Flexible Code Organization
Better Type Inference
Smaller Production Bundle and Less Overhead
You can still use the Options API, it won't be deprecated and is perfectly suitable for smaller projects.
I highly suggest reading this article about it: Why I Love Vue 3's Composition API.
I am working my way through the redux tutorial here. I have some experience with "traditional Flux" so the first codeblock looks familiar to me, but I am confused by the second statement.
In traditional Flux, action creators often trigger a dispatch when invoked, like so:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
In Redux this is not the case.
Instead, to actually initiate a dispatch, pass the result to the dispatch() function:
dispatch(addTodo(text))
dispatch(completeTodo(index))
If my action creator is this:
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
dispatch(addTodo(text))
Isn't that functionally equivalent to the first code example? Why does redux require the second way to actually dispatch?
Action Creators are used in Redux for adding extra layers of indirection and abstraction.
There are several reasons to use action creators rather than putting all your logic directly:
Encapsulation: Consistently using action creators means that a component doesn't have to know any of the details of creating and dispatching the action.
Abstraction: Put the logic for creating that action in one place.
Brevity: There could be some larger logic that goes into preparing the action object, rather than just immediately returning it.
Testability: It is easy to write tests for the component that pass in a mock version of the function instead. It also enables reusing the component in another situation.
Useful resources:
http://redux.js.org/docs/basics/Actions.html#action-creators
http://blog.isquaredsoftware.com/2016/10/idiomatic-redux-why-use-action-creators/
I've created some factory functions that give me simple (or more advanced) reducers. For example (simple one - base on action type set RequestState constant as a value):
export const reduceRequestState = (requestTypes: RequestActionTypes) =>
(state: RequestState = RequestState.None, action: Action): RequestState => {
switch (action.type) {
case requestTypes.start:
return RequestState.Waiting;
case requestTypes.success:
return RequestState.Success;
case requestTypes.error:
return RequestState.Error;
case requestTypes.reset:
return RequestState.None;
default:
return state;
}
};
Using those factory functions and combineReducers from redux I can compose them into fully functional reducer that handles most of my casual actions. That gives me readable code and prevents me from making silly mistakes.
Factories are good for common actions but when I need to add some custom behavior (for action type) which should modify some part of the store significantly I would like to write a custom part of the reducer that will handle that action for me.
The idea is to compose reducers in an iterate manner, so combineReducers but for an array. This way I could use my factories creating reducer and then combine it with my custom reducer that handles some specific actions. The combineReducers for an array would then call the first one, recognize that nothing has changed and call the second (custom) one to handle the action.
I was looking for some solution and found redux-actions but do not quite like the way it links actions and reducers making the semantics little different from what I'm used to. Maybe I do not get it, but eventually I like to see that my reducer is written as pure function.
I am looking for some hint that will show me the way.
Is there any library or project that uses any kind of higher order reducers and combines them in some way?
Are there any downsides regarding composing reducers like described above?
Yep, since reducers are just functions, there's an infinite number of ways you can organize the logic, and composing multiple functions together is very encouraged.
The "reducers in an array" idea you're looking for is https://github.com/acdlite/reduce-reducers. I use it frequently in my own app for exactly that kind of behavior - running a combineReducers-generated reducer first, then running reducers for more specific behavior in turn.
I've written a section for the Redux docs called Structuring Reducers, which covers a number of topics related to reducer logic. That includes useful patterns beyond the usual combineReducers approach.
I also have a list of many other reducer-related utilities as part of my Redux addons catalog.
I'm new to redux and looked at redux-actions or using switch statements in reducer, and though I'm not against using a switch statement, I'm wondering, isn't it easier to just use the call the action method?
Here's what I'm thinking
import actions from './actions'
const reducer = (state = {}, action) => {
if (actions[action.type]) return Object.assign({},
state, actions[action.type](action)
);
return state;
}
I've just tested this on my first reducer and action, and it works, but it seems quite obvious so I'm wondering why the switch type is the chosen way?
Switch statements are certainly the most common approach, but lookup tables are common as well. You can even use plain if/then conditions if you want. Ultimately, how you write your reducers is up to you.
FYI, this topic is covered in the Redux FAQ, in the FAQ: Reducers section. You might also want to read the new "Structuring Reducers" how-to section as well.
Some observations:
Don't refer to these external functions as "actions". They're not actions. They're actually reducers themselves.
Being reducers, you really ought to be passing the state object to them. Oftentimes, you'll want/need to utilise information contained in the current state, as well as information contained in the action object.
Otherwise, this seems like an appropriate approach.