Accessing Store within Redux and React Native app - javascript

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.

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.

how to go previous state without resetting state

I have a problem. I have an example1.js file that fetches data from DB in options. when I select the option data shown in table form.
when I click on the button to mark attendance it goes to another component e.g example2.js with param. but when I go back it must be in the same selected option. Anyone can help me. Code for go back is the following I am using.
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
const goback= () => { navigate(-1) };
You can use redux or for going back you can simply use the in built js function of history i.e history.back()
I highly recommend you to use Redux store for this: https://redux.js.org/
Using Redux(recommended approach). You can create your own state and write reducer to handle/set/change state.
In your component when you would like to receive the state you can use useSelector hook or connect, if want to change your state, use useDispatch, please read how to create a store and usage of hooks related to Redux: https://react-redux.js.org/api/hooks
Using context(not recommended for your purposes because it is not designed for high-performance/many actions. But it is easier to setup/use if you don't need a Redux).
Please read about context: https://reactjs.org/docs/context.html
All in all, you need to preserve your state 'somewhere' in Redux or Context to prevent refreshing the data while navigating/rerendering the component.
I you are not comfortable to use redux then try to use react reducers and context api together to create redux like structure. It helps maintaining states between different routes even on navigation.
You can refer these link.
https://hmh.engineering/using-react-contextapi-usereducer-as-a-replacement-of-redux-as-a-state-management-architecture-336452b2930e
https://blog.logrocket.com/react-hooks-context-redux-state-management/

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.

Should I use redux dispatch during initial rendering?

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.

How to share a single instance of an object among multiple actions?

I have a React/Redux application that talks alot to an API and deals with a lot of rarely changing data from a DB. In order to reduce traffic and improve UE, I now want to create a caching mechanism that stores data on the client by automatically using the best technology that is available (descending from IndexedDB to LocalStorage etc.).
I created a cache object that does an initial check which determines the storage mechanism (which gets saved to an engine property, so the check just needs to run once). It also has some basic methods save(key, value) and load(key), which then call the appropriate functions for the initially determined mechanism.
The cache object and its methods do work, but I wonder how to create the cache in my main index.js only once when the application loads, and then use this very object in my actions without recreating another cache object every time?
BTW: It feels wrong to make the cache part of my application state as it does not really contain substantial data to run the application (if there is no caching available, it falls back to just calling the API).
Do I need to inject the cache into my actions somehow? Or do I need to create a global/static cache object in the main window object?
Thanks for clarification and thoughts on this issue.
redux-thunk middleware offers a custom argument injection feature you could use.
When creating the store
const cache = createCache()
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(cache))
)
Then in your action creator
function getValue(id) {
return (dispatch, getState, cache) => {
// use cache
}
}

Categories

Resources