Should I use redux dispatch during initial rendering? - javascript

I'm trying to build a E-Commerce Store and it requires that I initially load a list of trending products on the home page.
Here, I can simply do without redux and simply display the data (roughly) of this sort
const trendingProducts = await get('/api/trendingProducts')
render(){
<TrendingProducts data={this.trendingProducts.data} />
}
I am using redux in my application. So should I do a dispatch elsewhere to fetch the trending products ?
All in all, Should I always handle every single fetch / render using only Redux dispatch ?

Redux is a store management for your application's state. Redux's dispatch is used to dispatching actions that aims to update your application's state in some way.
Hence if your application logic requires displaying information that belongs to your application's state - you need to take it from Redux store. If such information is not yet available into Redux store - you need to obtain it from some source (e.g. fetch) and use dispatch to update your application's state. If information, you're trying to display is not part of your application's state - you can display it directly, but in this case you'll need to handle React lifecycle events by yourself too since React re-draws components upon component's state change.
UPDATE: Your example code will work fine if you'll put your trendingProducts into component's state:
class MyComponent {
constructor() {
super();
this.state = {
trendingProducts: {}
}
}
componentWillMount() {
fetch('/api/trendingProducts').then(data => this.setState({trendingProducts: data}));
}
render() {
return (
<TrendingProducts data={this.state.trendingProducts}/>
)
}
}

That is very subjective and there is no correct answer but I can tell you by my experience.
Always keep your business logic separate from your component
If you're making API calls then you should definitely dispatch an action rather writing this in your component because there are lot of redux-like stores are emerging and it might happen that later you want to change your store using some different architecture. Your view layer should be independent on your API calls (business logic). In this way, while refactoring your app again, you'll just have to change the logic and your view will remain the same.
I'm writing this on my experience where we started refactoring the whole app from backbone to React. We had models and collections, we changed the whole html but we didn't change any business logic initially, just the views were deprecated but later we removed the business logic too using redux (iteratively). You should write your code in such a way that it has maximum reusability after all that's what React is and that's how you should write your front-end code.
Also, the component's state can reside in component where the whole app doesn't get affected. e.g. showing or hiding of a third-pane or overlay etc.

Related

How to share data between components in angular

I use observable to send a value from one component to another (data is sent to the subscriber after clicking on this other component, i.e. via subject) I subscribe in another component and everything works fine until I refresh the page, after refreshing the page the component is recreated and after recreation the subscriber has no data as he did not go through the first component.How can I solve the problem?
I tried using rxjs operators as shareReplay but it didn't work like shareReplay
As your Angular app is destroyed and rebuilt when the page is refreshed, unfortunately you will lose all user state that is not saved somewhere. This is a common problem in building UIs so there are a number of tools available to combat this
Strategy:
Store your user state when an important change is made. This is called persisting state
Fetch and reapply your saved state on reload. This is called hydrating state
Options:
Persist to local storage and check for local storage values on reload to hydrate with
Persist within the users URL (simple values only), e.g. modifying the URL in some way which can be checked on reload. Assuming you are dealing with a single page, query parameters or fragments may be the way to go
Persist to a database via a POST/PATCH call and perform a GET request on reload to check for values to hydrate with
None of these methods are inbuilt into an RxJS operator (as far as I know) but we can easily leverage RxJS to achieve any of the above strategies with little effort. The tap operator is often used specifically to handle side effects, i.e. operations which should happen as a coincidence of an RxJS emission. That is precisely what we want here, in simple terms:
"If the subject emits a value, also trigger an operation which
persists the user state"
"On page load, check for any available saved user state and emit via the
relevant subject, hydrating the observables which the components will consume"
See example implementation below
tab.service.ts
type TabType = 'first' | 'second'
#Injectable({
providedIn: 'root'
})
export class TabService {
tabSelectedSubject: BehaviorSubject<TabType> = new BehaviorSubject<TabType>('first')
tabSelected$: Observable<TabType> =
this.tabSelectedSubject
.pipe(
tap(tab: TabType) => {
// ... your persist code here
this.saveTab()
},
distinctUntilChanged()
)
constructor() {
// ... your hydrate code here
this.fetchAndApplyTab();
}
saveTab(): void {
localStorage.setItem('tab', tab)
}
fetchAndApplyTab(): void {
const savedTab: TabType | null = localStorage.getItem('tab');
if (savedTab) {
this.tabSelectedSubject.next(savedTab)
}
}
}
In this case, we are exploiting the fact that our service is:
A singleton, so only loaded once per app (i.e. provided in the app root)
The service will be instantiated in the first component that loads which also injects it
This allows us to put our fetchAndApplyTab() logic in tab.service.ts's constructor and keep the code self-contained. However, depending on your use case, you may instead want to run fetchAndApplyTab() from your component manually itself.
This is happening because everything is in memory, and on page refresh all is lost, due the fact that angular app is re-initializing. You need to persist the state, for example write it into local storage, for this you could use "tap" operator from rxjs. And also in loading you could read data from localstorage end emit-it, for this you could use app_initializer hook.
there are 2 days majority to pass data between components
If both components are interconnected it means the parent or child
relationships then you can pass data with input-output decorators.
you can use the common service to share data between 2 components.
In SPA application if you refresh the browser then all in memory objects and observables are not present you need to again go back to the screen where it will be initialize.

Run a component function every time its rendered

I've got an Ionic Angular app that calls an API every time the view changes and stores the value in ionic storage.
Every page has a 'header' component that is supposed to display this value from storage.
Inside ngOnInit(){} I fetch the value from storage and the value updates. However, it only does it once per page view. So if I view the homepage, for example, go to page 2, and back to the homepage, the code won't re-execute.
I imagine this is because the page doesn't actually unmount when you change the view, and therefore has no reason to 're-construct'.
constructor(){} only runs on the first construct for that view
ngOnInit() {} only runs the first init for that view
ionViewDidLoad() {} doesn't run because its not a view and that's an ionic page life cycle hook
I'm basically looking for a way to call an API, store the value in ionic storage, and on every page change, update the value in the header.
I've been thinking this might be achievable with Observables, but I'm not sure how this would work with ionic storage.
Or even get the value from storage in the view using one of the ionic view lifecycle hooks and pass it into the header as a prop, but that just seems messy.
The reason I'm using storage is that the balance gets used elsewhere and not just in the header and it saves me making the call multiple times if it's just available in storage.
Any recommendations appreciated
export class HeaderComponent {
balance = 0.00;
constructor(
private storage: Storage,
) { }
async ngOnInit() {
this.storage.get('balance').then(data => {
this.balance = data;
});
}
}
If you're positive that ngOninit in HeaderComponent is only firing once, then that means that it's not being destroyed between route changes. That would make sense if your component is present in all of your views.
I would not use local storage to distribute your application state to your app components. If your app state is relatively simple, then observables are the way to go. Create a service that holds the state of your application in an observable. Every time you fetch data from the API, push the new data to the observable. Then in your HeaderComponent subscribe to the observable in the ngOnInit hook so that your component data can be automatically synced to the application state any time there is a change.

How to share state (react)between electron's multiple windows?

I am developing a desktop app with react for UI and electron.
So, for now, I am fetching data from the server and saving it in the state using React's Context API to update the UI.
I am keeping the state and the function to add, remove and update state in the renderer process and with IPC I am sharing the data between renderer process through main process (as it should be).
But as the application is scaling I need a better approach. Something like a central state (if that's a thing).
P.S. can I use a database along with the Electron app if there is any real-time database such as rxdb?
I had this exact same problem and I used electron-redux (https://github.com/hardchor/electron-redux).
I was also using react for my UI.
I ran into the same situation where I needed a single redux store for all my react renderer process in electron.
I tried electron-redux but that did not work for me as react complains about the snippet of code you need to put in the renderer process.
nice solution:
After some search I ran into redux-state-sync which is a redux middleware that used to synchronize the redux store and actions across multiple react tabs, which works nicely with electron as the tabs here are the different renderer process.
The only hindrance is to initialize the store in the newly created window, that can be done by sending the store state with an ipc call from the main window that opens the new one, that dispatches an action to update the state.
This initialization approach works nicely in react#17.0.0 , but for some reason it doesn't in react react#18.0.0
The best way to have a 'master state' is to use React-Redux.
Redux can do what Context does and more. It also has lots of libraries for listening for realtime updates from servers. The most popular at the time is React-Redux-Firebase, which connects your Redux store with your Firebase database.
Most developers agree on the fact that Redux takes some time to set up, but is definitely worth the time invested. I have personally used React-Redux-Firebase and I can assure you that all real-time updates will be in your Redux store within 250ms.
Firebase is also free up to a certain point (check Firebase Pricing).
In order to access your Redux state in a component, your need to follow 3 steps:
STEP 1: Create a mapStateToProps const that contains all the stuff you want from your store.
const mapStateToProps = state => ({
customers: state.customers,
books: state.books
})
STEP2: Create an actions const that contains any functions you have in an actions.js or similar file and you want to call
import { fetchCustomers } from './actions.js'
const actions = {
fetchCustomers
}
Remember that any fetching from your API can (and should) be done from there.
STEP 3: Export your component with Redux's connect function, including your mapStateToProps and actions consts.
export default connect(mapStateToProps, actions)(myComponent);
Redux is rather complicated to be explained in a single stackoverflow answer, so I suggest you take a look at the docs or follow a tutorial. You should be able to figure everything out in your first or second day of development. It is absolutely worth the time.

React SPA. API for global state store for handling login state?

So I have this React component at the root of my website that is login and the page let's call it A. If login is successful it sets the login state to true then switches to another page and then down that tree of those pages(So let's say I have A then B is A's child and C is B's child). Let's say at C I make a rest call to the backend and get back 401 (For whatever reason they're not allowed or their token expired), then I know that the person should not be logged in so it should automatically set the login state at A to false.
I was wondering if there was a way to do this with a global state manager? Something I guess similar to Redux but Redux requires you to pass the store down the component tree as well which I feel is a bit cumbersome and harder to organize well. It'd be nice if I could have a global state store that I can just import.
This is the scenario where you should be using stores to maintain the authentication state across your app. You can simply inject it into any component and update the values, and have it referenced by any other component that needs to check.
If you aren't at the point of learning stores quite yet, the way you do this is to store state in the parent component:
this.state = {
authorised: false,
}
then add a function to update this:
setAuthorisation(value){
this.setState({authorised: value})
}
Now all you have to do is pass both these down to your child components and they can be updated and referenced at any time
<Child authCallback={this.setAuthorisation} isAuthorised={this.state.authorised} />
You should really be researching this on your own, as it is one of the basics of react :)

Accessing Store within Redux and React Native app

I'm starting to develop an app that will be making calls to an API that will require the inclusion of a JWT that I plan on storing within the Redux store.
Typically you can access the Redux store by mapping a particular part of the store to a component's state with mapStateToProps() and connect(), however I'd like to access the Redux store within a file that will not end up being a React component/container - just a pure js file that will be handling the API calls.
Is this possible?
You can use the getState() function of the store returned by createStore. You can use this inside a function that fishes the needed data from the state.
const myImportantData = () => store.getState().my.deep.data;
The version above uses the store directly, as in a global variable. This prevents you from using more than one store in your process. Normally this is what you want, but this isn't true when running on the server. That said, on the server you'll likely not need the JWT access anyway.
If you do need to swap stores, however, then you can pass it as a parameter or close over a store local variable:
const getDataGrabber = store => () => store.getState().my.deep.data;
Yes, it is possible.
Redux is framework agnostic, although it was made with React in mind.
The mapStateToProps() and connect() methods aren't part of the core Redux library but of the helper library 'React-Redux' which provide bindings specifically for Redux use within React.
It's worth checking out Dan Abramov's Getting started with Redux series to get the principle of how the guts of Redux works.
An example of which are Video 6 and Video 7 where he discusses the Redux store and describes the three methods that make it up:
store.getState // gets the current application state
store.dispatch // changes the current application state by dispatching an action
store.subscribe // suscribes to changes and re-renders the app using the
// current state
The videos go into a fair bit of detail as to how to register the reducers with the store, so the series should prove very helpful.

Categories

Resources