I am relatively new to React with Typescript so I was following the video which was made by Mark Erikson and Jason Lengstorf on the Redux Toolkit website. Here is the link incase you want to see it.
At approximately 45 minutes in, Mark mentions two constructs which can be seen in the image below. (lines 4 and 5).
See picture
I had some trouble understanding these constructs so I made my own counter example using redux toolkit. I did not have to use the typecasts as Mark did. I just want someone to confirm that what I did is also OK and perhaps explain the differences. My code can be found in this Code Sandbox Link.
Basically the exports in the store look like this :
// Export for provider in App.tsx
export const appStore = configureStore({ reducer: { counterReducer } });
// Export dispatch
export const appDispatch = appStore.dispatch;
export const appState = appStore.getState();
Here is how the state is consumed :
let counterValue = useSelector(
(state) => appStore.getState().counterReducer.value
);
And finally I use this code to dispatch the action:
appDispatch(add(1));
Thanks in advance.
Related
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
);
I'm using redux-tookit for state.
My action:
const updateSomething = (data: string) => async (dispatch) => {
await user.set({ data })
dispatch(updatedData(data))
}
In my view I want to do something like:
const dispatch = useDispatch()
await dispatch(updateSomething('Hi!'))
Update 5 July 2021
TL;DR
If typeof store.dispatch still doesn't give you the right typing with ThunkDispatch as one of the overloaded options, you may consider manually typing it, like so: -
export type AppDispatch = ThunkDispatch<AppState, null | undefined, AnyAction> &
Dispatch<AnyAction>;
Note: This is the correct typing with the default middleware, if you have added more middlewares you should try to figure out the possibilities.
Background
While my proposed solution (below) works in codesandbox, it doesn't work in my project, which I ported from vanilla redux to redux toolkit. Maybe some of the packages installed break the types, just a speculation but when I include redux-debounced in my codesandbox sample (link below), the type for store.dispatch is falled back to Dispatch<AnyAction>, even without including redux-debounced in middleware.
This is certainly a mystery that has to be resolved!!
I had the similar issue as TS, so I made a simple project in codesandbox and surprisingly it works with a minor tweak!
In my view, what TS meant is that updateSomething('Hi!') is a valid thunk created using createAsyncThunk() in redux toolkit, where dispatching the thunk should return a Promise. That's a feature in redux toolkit. But unfortunately, somehow typescript is returning AsyncThunkAction and invoking the following line:
await dispatch(updateSomething('Hi!'));
actually yields a typing error. Here's what I got in my codesandbox project:
In my case, fetchDynamicName() is a valid thunk and supposedly the type of dispatchReturn should be a Promise.
With a minor tweak found in this post, it actually works!!
All we need is to export the dispatch type of the store, like so:
export type AppDispatch = typeof store.dispatch;
and assign the type to the dispatch function before using it:
const dispatch: AppDispath = useDispatch();
And voilà! See the screenshot below:
You can take a look at my codesandbox project at https://codesandbox.io/s/fast-cdn-08vpu?file=/src/App.tsx.
There are possible duplicates of this question but they don't quiet answer my question well. So I decided to start a new thread.
So I am trying to create a simple basket component for an e-commerce application....
Following is the code for reducers and action files:
actions.js
export const incrementQuantitySuccess = (basketProducts) =>{
return {
type: actionTypes.INCREMENT_QUANTITY_SUCCESS,
basketProducts:basketProducts
}
}
export const incrementQuantity = (line) => {
return (dispatch,getState) => {
/*LOGIC for increment quantity*/
const basketProducts = getState().basket.productsInBasket;
const updatedBasketProducts = basketProducts.map((product) =>{
if (product.id === line.id){
product.quantity += 1;
product.total = product.quantity * product.price;
}
return product;
});
/***************/
dispatch(incrementQuantitySuccess(updatedBasketProducts));
}
}
reducer.js
const incrementQuantitySuccess = ( state, action ) => {
return updateObject(state,{
productsInBasket:action.basketProducts,
loading:false
});
}
const reducer = (state= initialState,action) => {
switch(action.type){
case actionTypes.GET_BASKET: return getBasket(state,action);
case actionTypes.INCREMENT_QUANTITY_SUCCESS: return incrementQuantitySuccess(state,action);
default:return state;
}
}
export default reducer;
Right now I have put the increment quantity logic in my action.js file.
I found various advises regarding keeping a balance between reducers and action creators when it comes to distributing business logic, where as some told to keep reducers stupid and dumb.
My question is where should the Logic for increment go? I went through couple of articles,on redux.js.org, on where the business logic should be but I am still not clear about it.
Also is this particular use-case I am not sure if I need middleware like redux-logic.
I am new to react. Kindly guide regarding this.
Thanks in advance
One of practices says that you should keep your reducers and actions pure and the real side-effect should happen inside your middlewares. With this approach you will keep the actions and reducers nice and clean and you can fully focus on your middlewares because they will become the only place, where side-effects can happen.
I was really amazed when I watched presentation from Nir Kaufman and I'm encouraging you to watch his speak at ReactNYC Advanced Redux Patterns - Nir Kaufman # ReactNYC. This video helped me a lot when I was struggling with Redux the most.
Also there is second speak about Redux and middlewares from Nir. You can check the second one here Advanced Redux: Design Patterns and Practices - Nir Kaufman | JSHeroes 2018
Hope it will help!
I am new to React, Redux and JS overall. I want to know how can I chain actions in a component? On a listing screen, my application retrieves user's Geo Position then it fetching api url with current long and lat.
I made it with time out. But I see it's a risky way.
import {
aFetch,
aGetPosition,
} from '../../actions';
import { API_URL } from '../../config/ApiEndpoints';
class App extends Component {
componentDidMount() {
this.props.aGetPosition();
setTimeout(() => {
const { latitude, longitude } = this.props.position.data.coords;
const url = `${API_URL}=${latitude},${longitude}`;
this.props.aFetch(url);
}, 1000);
}
render(){...}
}
const mapStateToProps = (state) => {
return {
position: state.position,
items: state.items,
};
};
export default connect(mapStateToProps, { aFetch, aGetPosition })(App);
Is possible to make it using .then() or something equal?
I believe you need the method componentWillReceiveProps(). The docs provide a good explanation about it and other methods in the lifecycle of a component.
Firstly, you'll want to dispatch your redux actions. This is possible by using a mapDispatchToProps function, which will be the 2nd parameter in your connect function (instead of a plain object with your actions, which is what you have now). Docs on implementing redux within your React containers, including dispatching actions from your container: http://redux.js.org/docs/basics/UsageWithReact.html#implementing-container-components
To handle async actions and chaining actions, you'll likely want to use a middleware to help you, such as redux-thunk. Doc link: http://redux.js.org/docs/advanced/AsyncActions.html#async-action-creators (I recommend reading this whole page, but the link will go directly to the section for redux-thunk).
Example code: https://github.com/d6u/example-redux-update-nested-props/blob/master/one-connect/index.js
View live demo: http://d6u.github.io/example-redux-update-nested-props/one-connect.html
How to optimize small updates to props of nested component?
I have above components, Repo and RepoList. I want to update the tag of the first repo (Line 14). So I dispatched an UPDATE_TAG action. Before I implemented shouldComponentUpdate, the dispatch takes about 200ms, which is expected since we are wasting lots of time diffing <Repo/>s that haven't changed.
After added shouldComponentUpdate, dispatch takes about 30ms. After production build React.js, the updates only cost at about 17ms. This is much better, but timeline view in Chrome dev console still indicate jank frame (longer than than 16.6ms).
Imagine if we have many updates like this, or <Repo/> is more complicated than current one, we won't be able to maintain 60fps.
My question is, for such small updates to a nested component's props, is there a more efficient and canonical way to update the content? Can I still use Redux?
I got a solution by replacing every tags with an observable inside reducer. Something like
// inside reducer when handling UPDATE_TAG action
// repos[0].tags of state is already replaced with a Rx.BehaviorSubject
get('repos[0].tags', state).onNext([{
id: 213,
text: 'Node.js'
}]);
Then I subscribe to their values inside Repo component using https://github.com/jayphelps/react-observable-subscribe. This worked great. Every dispatch only costs 5ms even with development build of React.js. But I feel like this is an anti-pattern in Redux.
Update 1
I followed the recommendation in Dan Abramov's answer and normalized my state and updated connect components
The new state shape is:
{
repoIds: ['1', '2', '3', ...],
reposById: {
'1': {...},
'2': {...}
}
}
I added console.time around ReactDOM.render to time the initial rendering.
However, the performance is worse than before (both initial rendering and updating). (Source: https://github.com/d6u/example-redux-update-nested-props/blob/master/repo-connect/index.js, Live demo: http://d6u.github.io/example-redux-update-nested-props/repo-connect.html)
// With dev build
INITIAL: 520.208ms
DISPATCH: 40.782ms
// With prod build
INITIAL: 138.872ms
DISPATCH: 23.054ms
I think connect on every <Repo/> has lots of overhead.
Update 2
Based on Dan's updated answer, we have to return connect's mapStateToProps arguments return an function instead. You can check out Dan's answer. I also updated the demos.
Below, the performance is much better on my computer. And just for fun, I also added the side effect in reducer approach I talked (source, demo) (seriously don't use it, it's for experiment only).
// in prod build (not average, very small sample)
// one connect at root
INITIAL: 83.789ms
DISPATCH: 17.332ms
// connect at every <Repo/>
INITIAL: 126.557ms
DISPATCH: 22.573ms
// connect at every <Repo/> with memorization
INITIAL: 125.115ms
DISPATCH: 9.784ms
// observables + side effect in reducers (don't use!)
INITIAL: 163.923ms
DISPATCH: 4.383ms
Update 3
Just added react-virtualized example based on "connect at every with memorization"
INITIAL: 31.878ms
DISPATCH: 4.549ms
I’m not sure where const App = connect((state) => state)(RepoList) comes from.
The corresponding example in React Redux docs has a notice:
Don’t do this! It kills any performance optimizations because TodoApp will rerender after every action.
It’s better to have more granular connect() on several components in your view hierarchy that each only
listen to a relevant slice of the state.
We don’t suggest using this pattern. Rather, each connect <Repo> specifically so it reads its own data in its mapStateToProps. The “tree-view” example shows how to do it.
If you make the state shape more normalized (right now it’s all nested), you can separate repoIds from reposById, and then only have your RepoList re-render if repoIds change. This way changes to individual repos won’t affect the list itself, and only the corresponding Repo will get re-rendered. This pull request might give you an idea of how that could work. The “real-world” example shows how you can write reducers that deal with normalized data.
Note that in order to really benefit from the performance offered by normalizing the tree you need to do exactly like this pull request does and pass a mapStateToProps() factory to connect():
const makeMapStateToProps = (initialState, initialOwnProps) => {
const { id } = initialOwnProps
const mapStateToProps = (state) => {
const { todos } = state
const todo = todos.byId[id]
return {
todo
}
}
return mapStateToProps
}
export default connect(
makeMapStateToProps
)(TodoItem)
The reason this is important is because we know IDs never change. Using ownProps comes with a performance penalty: the inner props have to be recalculate any time the outer props change. However using initialOwnProps does not incur this penalty because it is only used once.
A fast version of your example would look like this:
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider, connect} from 'react-redux';
import set from 'lodash/fp/set';
import pipe from 'lodash/fp/pipe';
import groupBy from 'lodash/fp/groupBy';
import mapValues from 'lodash/fp/mapValues';
const UPDATE_TAG = 'UPDATE_TAG';
const reposById = pipe(
groupBy('id'),
mapValues(repos => repos[0])
)(require('json!../repos.json'));
const repoIds = Object.keys(reposById);
const store = createStore((state = {repoIds, reposById}, action) => {
switch (action.type) {
case UPDATE_TAG:
return set('reposById.1.tags[0]', {id: 213, text: 'Node.js'}, state);
default:
return state;
}
});
const Repo = ({repo}) => {
const [authorName, repoName] = repo.full_name.split('/');
return (
<li className="repo-item">
<div className="repo-full-name">
<span className="repo-name">{repoName}</span>
<span className="repo-author-name"> / {authorName}</span>
</div>
<ol className="repo-tags">
{repo.tags.map((tag) => <li className="repo-tag-item" key={tag.id}>{tag.text}</li>)}
</ol>
<div className="repo-desc">{repo.description}</div>
</li>
);
}
const ConnectedRepo = connect(
(initialState, initialOwnProps) => (state) => ({
repo: state.reposById[initialOwnProps.repoId]
})
)(Repo);
const RepoList = ({repoIds}) => {
return <ol className="repos">{repoIds.map((id) => <ConnectedRepo repoId={id} key={id}/>)}</ol>;
};
const App = connect(
(state) => ({repoIds: state.repoIds})
)(RepoList);
console.time('INITIAL');
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('app')
);
console.timeEnd('INITIAL');
setTimeout(() => {
console.time('DISPATCH');
store.dispatch({
type: UPDATE_TAG
});
console.timeEnd('DISPATCH');
}, 1000);
Note that I changed connect() in ConnectedRepo to use a factory with initialOwnProps rather than ownProps. This lets React Redux skip all the prop re-evaluation.
I also removed the unnecessary shouldComponentUpdate() on the <Repo> because React Redux takes care of implementing it in connect().
This approach beats both previous approaches in my testing:
one-connect.js: 43.272ms
repo-connect.js before changes: 61.781ms
repo-connect.js after changes: 19.954ms
Finally, if you need to display such a ton of data, it can’t fit in the screen anyway. In this case a better solution is to use a virtualized table so you can render thousands of rows without the performance overhead of actually displaying them.
I got a solution by replacing every tags with an observable inside reducer.
If it has side effects, it’s not a Redux reducer. It may work, but I suggest to put code like this outside Redux to avoid confusion. Redux reducers must be pure functions, and they may not call onNext on subjects.