I'm new to Redux and started with ngrx. I'm unable to understand the meaning of this line of code store.select:
clock: Observable<Date>;
this.clock = store.select('clock');
In very simple terms select gives you back a slice of data from the application state wrapped into an Observable.
What it means is, select operator gets the chunk of data you need and then it converts it into an Observable object. So, what you get back is an Observable that wraps the required data. To consume the data you need to subscribe to it.
Lets see a very basic example.
Lets define the model of our store
export interface AppStore {
clock: Date
}
Import the Store into your component from '#ngrx/store'
Create a store by injecting into the constructor
constructor(private _store: Store<AppStore>){}
Select returns an Observable.
So, declare the clock variable in your component as follows:-
public clock: Observable<Date>;
Now you can do something like follows:-
this.clock = this._store.select('clock');
Wow, this is a big topic. So basically "select" is really a RXJS operator that is used in this case to retrieve the value of a part of the application state object. So say your main app state has a array of users and a array of security functions. "Select" allows you to get a reference to a observable whose value is just that array of users. Before you get into ngrx you really need to study up on Observables and RXJS. I found this article linked off of the main Github project page for ngrx helpful.
https://gist.github.com/btroncone/a6e4347326749f938510
RXJS and redux can be a big topic but I suggest working on your knowledge in small bite size chunks. It took me about 2 months of working with it before I really started to feel comfortable. Even if you don't stay with ngrx, understanding how RXJS works is incredibly useful and is worth the time investment to learn it.
Here is a gist article that also gives a good intro into RXJS.
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
It returns the state called 'clock'.
Here is an example. In the constructor store.select is called, this time with 'todos'.
https://github.com/btroncone/ngrx-examples/blob/master/todos/src/app/todo-app.ts
export class TodoApp {
public todosModel$ : Observable<TodoModel>;
//faking an id for demo purposes
private id: number = 0;
constructor(
private _store : Store<AppState>
){
const todos$ = _store.select<Observable<Todo[]>>('todos');
const visibilityFilter$ = _store.select('visibilityFilter');
...
In the bootstrap, provideStore is given APP_REDUCERS
import {bootstrap} from '#angular/platform-browser-dynamic';
import {TodoApp} from './todo-app';
import {provideStore} from "#ngrx/store";
import * as APP_REDUCERS from "./reducers/reducers";
export function main() {
return bootstrap(TodoApp, [
provideStore(APP_REDUCERS)
])
.catch(err => console.error(err));
}
APP_REDUCERS is all the reducers defined. The todos reducer is defined as follows:
import {ActionReducer, Action} from "#ngrx/store";
import {Todo} from "../common/interfaces";
import {ADD_TODO, REMOVE_TODO, TOGGLE_TODO} from "../common/actions";
export const todos : ActionReducer<Todo[]> = (state : Todo[] = [], action: Action) => {
switch(action.type) {
case ADD_TODO:
return [
...state,
action.payload
];
There are a few ways to do this, and you can compose a list of all your reducers, essentially defining a series of object keys that refer to a reducer object.
Store.select returns an observable that you can subscribe to either in your component or template via '|async'.
This.store.select('keyname') will return the data from store object of 'keyname' property has. you can further look for inner object in store using multiple reducer with StoreModule.forFeature("master", masterReducer) in main module with createSelector
export const getMasterState = createFeatureSelector<myModels.MasterState>('master');
export const getMatserBranchList = createSelector(
getMasterState,
(state: myModels.MasterState): myModels.Branch[] => state.branchList
);
Related
My understanding after reading the documentation is that in order to obtain values from an NgRx store, we have to use selectors. So far, I've had luck doing that, only with a small issue regarding typing, which makes me worried if my implementation is incorrect in any way.
So, let's say I want to retrieve a number value from the store, id for example. In my componentName.component.ts I would access this value like this:
id$ = this.store.select(selectId);
where selectId is defined from another file as:
export const selectData = (state: AppState) => state.data;
export const selectId = createSelector(
selectData,
(state: DataState) => state.id,
)
I am able to access id$ in my HTML component easily by doing {{id$ | async}}, but accessing it from the component class itself has proven a bit more difficult. For starters, the variable type is Observable<number> instead of just number, and that makes it hard to use it in cases where it needs to be of number type, such as when comparing it:
ngOnInit(): void {
console.log(this.id$ === 0);
}
The TypeScript error I get from the code above is:
TS2367: This condition will always return 'false' since the types
'number' and 'Observable ' have no overlap.
And console-logging id$ itself confirms that it is indeed of Observable type, so this leads me to believe I am doing something wrong, but I'm unsure exactly what. Any help is appreciated!!!
id$ is an Observable, and you can access its value by subscribing to it from the component class using subscribe function, or from the component template using async pipe.
In Component Class:
ngOnInit(): void {
this.id$.subscribe(id => console.log(id));
}
In Component Template:
<span>{{ id$ | async }}</span>
Check the official docs of Angular about Observable(s):
https://angular.io/guide/observables
I just learned react and react-native for 3 months , and i highly familiar with functional component, from EVERYTHING, because from first step, i already write a "hello world" in function, and unitl now, i still stick with function, because, i read some blog, and with hooks, learn classes are optional, so i decided to focus on functional component. But when i start to learn MobX, i feel a little bit confuse and struggle, especially with store:
class TodoStore {
todos: Todo[] = []
constructor() {
makeObservable(this, {
todos: observable,
unfinishedTodoCount: computed,
addTodo: action
})
}
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.done).length
}
addTodo(todo: Todo) {
this.todos.push(todo)
}
}
A silly-old question, but how constructor() use in functional component? Is that state? But how to apply with mobX, how to convert above class to function or can we just use function for all mobX concept?
Please help, thank you a lot
Functional programming without dynamic state is just a big function that return the same value for the same parameters.
In React you do have state that is stored in React instance itself, every time that you use setState React saves that value for future renders. it's holding the state for you.
As for MobX, you have to create an instance of an observable object and provide access to it to your components, so they can change it/interact with it.
The best practice for this, is to create an object instance out of a class and provide that instance to your components via the context api. (Read about it, if you don't know how to use it)
You CAN create a simple JavaScript object and make it observable using makeObservable(obj), but again. the best practice is to create a class and in the constructor call makeObservable(this).
Here's an example for a simple class Store:
class AgeStore {
#observable age: number = 12;
constructor() {
makeObservable(this);
}
#action
grow() {
this.age++;
}
}
And this is how you would initialize your React app (You should split this to several files):
const ageStore = new AgeStore();
const AppContext = createContext(null);
export function useAgeStore() {
return useContext(AppContext);
}
ReactDOM.render(
<AppContext.Provider value={ageStore}>
<App />,
</AppContext.Provider>
document.getElementById('app'),
);
And this is how your functional components should use the store:
export const DemoComp: React.FC = observer(function DemoComp() {
const ageStore = useAgeStore();
return <div>
<div>The current Age is:{ageStore.age}</div>
<button onClick={ageStore.grow()}>Grow</button>
</div>;
});
I have a question that what is the difference between use getState from store directly or use mapStateToProps. Please look at me example below
import React, { Component } from 'react'
import store from '../store'
import { connect } from 'react-redux';
class Test extends Component {
constructor(props) {
super(props);
}
render() {
return (
<p>
<h1>{this.props.count}</h1>
<h2>{store.getState().reducer1.count}</h2>
</p>
)
}
}
const mapStateToProps = (state) => ({
count: state.reducer1.count
});
// export default Test;
export default connect(mapStateToProps)(Test);
Both store.getState and mapStateToProps above work normally, it still updates when state change. If we just use getState only, we don't need to use connect method.
Another point I've recognized is when use mapStateToProps with connect, in reducer we must return a new copy of object state than return that state with modification. If not, component will not update when state changed. Like this:
return Object.assign({}, state, {
count: state.count + 1,
payload: action.payload,
});
But if we use store.getState(), we can either return a new copy or the revised one. Like this:
state.count++;
state.payload = action.payload;
return state
Anyone know please explain to me, thank you.
P/S: and similar with store.dispatch vs mapDispatchToProps, those 2 will work normally, just want to know why we should use mapToProps with connect instead of call the function directly from the store.
mapStateToProps is just a helper function which is really helpful to manage the project in modular style. For example, you can even place all the logic of connect in separate files and use where you want.
Suppose if you're working on a large scale application, then guess a sorts of properties nested there. Using connect you're actually modularizing project which is very helpful for developers who watch the project.
If you don't, you're writing several lines of code in single file.
A possible problem you'll face when using getState() or dispatch() directly. See this post for a little help to make it clear.
The key benefit using connect is that you don't need to worry about when state is changed using store.subscribe(), the connect will let you know each state change whenever it gets updates.
Also, react core concept is based on props and states. Using connect allows you to get redux state as props. Using this.props :)
And ah, I remembered at what condition I accessed the store directly rather than using connect. In my project, I needed to save all the redux state in different form to somewhere and I din't need to connect it to any component. In this case, direct usage with redux store is very easy and helpful. But if we try the same with connect in this case, then we'll have a difficult time.
Thus, I would suggest you to use them in separate condition.
Use connect if you want to map with component.
Access redux store directly if you don't need to map with component.
Further, this blog will explain a bit more: react redux connect explained
Redux Flow:
Using connect with react component:
To conclude: Using connect, you use the provider and it lets the every child component to access the store by providing a provider and using store props in root app component.
I am new to react-redux and I was surprised to see an example where a function, in this case being getVisiblieTodos, is called inside mapStateToProps. This function should be called in a reducer since it changes state? Is the code breaking "good form" for the sake of brevity? Is it okay to do this in general?
I am looking at code from this link
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
In redux we want the store to hold the minimal data needed for the app. Everything that is derived from the base data, should be computed on the fly, to prevent cloning pieces of the store, and the need to recompute all derived data when something changes in the store.
Since the visible todos list is not part of the store, but computed using the list of todos, and the visibilityFilter, the getVisibleTodos() doesn't change the store's state. It produces the derived computed data from the those two properties.
A function that is used to get data from the store, and compute derived data is known as a selector. Using selectors, the derived data is not part of the store, and computed when needed. In addition, we can use memoized selectors, to save the computation overhead.
You may see getVisibleTodos as a reducer because it includes "switch .. case" block or/and because it has 2 arguments . However, it is not a rule.
A redux reducer ( by definition) changes store state according to dispatched action , and that's why it takes two arguments ( store state + dispatched action ) and it returns new state for the store without mutation.
getVisibleTodos here is a helper function which filter an array according to string (filter).
Also , filter is not a redux-action, it is just string that decides todos to be rendered.
I may agree with you it is something weird , and if we can see the whole application (reducers, actions,... ) we can decide if it is best practices or not .
todos in this component is a calculated property based on the state of the reducer, and it is not changing any state.
It's okay to transform properties comming from recuders that are used only by one component (they are called selectors). Imagine that you use todos in other components, you will not want to make changes in one component like filtering and seeing that in the other components. If this is the case, it's fine to do it.
Also, it is a good property of your reducer to store only the needed data. More state is more complexity in the app, and more overhead to calculate new states.
It seems to me that a function should do what its name says, nothing less, nothing more.
mapStateToProps() should just do that, ie "map", and should normally not call other functions.
Update
Thanks to #Dominic Tobias and #gabdallah for spotting my embarrassing mistake.
The correct answer is of course;
so try checking action.payload.
The other comments regarding the switch statement and the action object we're referring to errors I made in my example, which I've since corrected.
Imagine I've combined the the following two reducers;
import { combineReducers } from 'redux'
import { routerStateReducer } from 'redux-router'
import entries from './entries'
export default combineReducers({
router: routerStateReducer,
entries
})
I would like to mutate the entries state based on another part of the global state, in this case; the router state provided by redux-router in order for example to implement pagination.
How could I do something like this?
// entries.js
import { ROUTER_DID_CHANGE } from 'redux-router/lib/constants'
const initialState = {}
function entries (state = initialState, action) {
switch (action.type) {
case ROUTER_DID_CHANGE:
// How can I access `state.router` here in order to do something like this;
if (routerState.location.pathname === '/entries') {
return {
...state,
page: routerState.location.query.page || state.page,
limit: routerState.location.query.limit || state.limit
}
}
return state
}
}
Some other approaches that come to mind;
connect the router state to the Entries route component, use the componentWillMount lifecycle method to check router state and call an action creator with the page and limit values mutating the entries state in turn. This would work; however I'm using some transition middleware to call a static fetchData method on the route component prior to mounting it, so the data get's fetched, then the pagination action creator would be called afterwards; not the desired behaviour.
listen to router actions somewhere else (i.e a dedicated router redux module), call an action creator on the entries store, but I'm not sure how well this fits with redux-router or how I would get access to the router part of the global store.
don't do this at all; simply query the router state in the static fetchData method
Other useful info;
The implementation in question is Universal App heavily inspired by react-redux-universal-hot-example
Relevant deps
react 0.14.2
redux 3.0.3
react-router 1.0.0-rc3
redux-router 1.0.0-beta3
How can I achieve this or similar behaviour? Am I even thinking about this the right way?
Back in the old days before things got simpler for a developer people would listen to the popstate event on the history object ;)
It looks like the required info is on the action?
history.listen((error, nextRouterState) => {
...
store.dispatch(routerDidChange(nextRouterState));
and the action:
export function routerDidChange(state) {
return {
type: ROUTER_DID_CHANGE,
payload: state
};
}
So try checking action.payload.
However your switch statement is using action instead of action.type so there's something fishy going on there.. You shouldn't need to do action = {} either - see http://redux.js.org/docs/basics/Reducers.html