How do we persist redux store without using localstorage and make full reactjs web application work offline - reactjs

I have to do full offline functionality like all redux store data should remain after page refresh/offline(network connection lost).
When user goes offline previously stored data should be used in viewing pages & for suppose i have big forms(ex: employee form with all work experience and personal details)suddenly if user loose network, data should not be lost.. should be saved somehow & after that when user is online have to store data to DB
I am using react -18.0.0 version with react-redux & redux-saga.What are the possible ways?

lets say users are required to log in to system .once login is successfull save that
data to local storage then dispatch loginsuccess with user and token as payloads
execute a function inside useEffect in app.js to get back saved data from local storage and dispatch
loginsuccess with those data
inside signup function:
let res=await axios.post("/signin",{user});
let{user,token}= res.data;
localStorage.setItem("user", JSON.stringify(user));
localStorage.setItem("token",token);
dispatch({ type: "loginsuccess",payload:{user,token}});
inside app.js :
useEffect(() => {
dispatch(isUserLoggedIn());
}, []);
inside isUserLoggedIn :
const localstorage = localStorage.getItem("user");
if (localstorage) {
const user = JSON.parse(localStorage.getItem("user"));
dispatch({ type: "loginsuccess",payload:{user}});
} else {
dispatch({ type: "loginfailed",payload:{error:"please log in"}});
}

One way can be to store your form(or state) in localstorage. Another way can be use library redux-persist .
I think your question is similar to the one asked here. Have a look here for more ideas.

Another approach to store your data, is to make use of the IndexedDB API, it already has a great support on the latest browser versions caniuse.
There is a really good library that make use of this api but
combined with promises idb.
After picking up how you're gonna do it, you can have a watcher saga that reacts to the online / offline status and do the appropriated synchronization.
Also I think it's important to mention that all of the above will only take care of the data, you still need to make sure to make the JS and CSS to be available offline. on web.dev there is a great induction on this subject.

Related

How to properly save sensitive data on frontend using next.js?

I'm building a web app that has role permissions based, admin, user and also products, product A, B, C, etc. I get these data from a backend api.
Currently, I'm using local storage and useContext hook to save and manipulate these data, but an user that knows it, can easily change this information and manipulate the front end, so I'm wondering now which approach I can use here.
My wish (if it's possible) is to get these information by backend after the login, and reuse the data freely in other components, just importing it, like an useContext hook.
I know that there is Redux, but since I'm using next.js, from what I saw, every rendering it will lose/refresh data, so it won't be usefull here.
I'm also using SWR, so, I tried to get these data from cache.get('key'), but the SWR call must be on the same component to get the data properly from the key cached. It's not working if a call the SWR on the e.g home page, and try to get it in other generic component.
What do you people suggest to go here?
Thanks!
I think you should authenticate your user, then store their access key and identifier in localStorage and global state.
When users access an authorization required page.
You'll check for the access token if it doesn't exist on both global state and localStorage. Redirect (or alert) the authorization error.
If there is an access token. Then send a request to the server with that access token. The server will be in charge of authorizing progress. And you will handle the logic on the front end based on the response from the server.
The thing is the authorization (checking permission for instance) should be done in the backend, not on the frontend
I don't know whether you can manipulate the implementation of the backend API or not. Hope it helps
Following the answers, I created a useContext to use in any component that I need.
Here is what I have in my context:
const [userRoles, setUserRoles] = useState<string[] | undefined>([])
const getUsersRoles = useCallback(async () => {
const getUserRoles = await UsersService.getUsersRoles(userInfo.idUsuario)
setUserRoles(getUserRoles.data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
Note: UsersService.getUsersRoles function is integration with the API
And how I use it in the component I need:
const { userRoles, getUsersRoles } = useAuth()
if (userRoles?.length === 0) {
getUsersRoles()
return <LoadingGIf tip="Carregando opções..." />
}
With this, I have the data I need here userRoles. And IF the user reload/refresh the page, getUsersRoles is requested and set the data to the userRoles
The downside to this, at least for me, is that I have to add this:
const { userRoles, getUsersRoles } = useAuth()
if (userRoles?.length === 0) {
getUsersRoles()
return <LoadingGIf tip="Carregando opções..." />
}
for every component I need to use the roles data, but I believe that's it. It's working fine and isn't request extra any endpoints of API.
If anyone has a contribuitions or improves to do in the code, fell free to do it.

Storing E-Commerce Product Data On LocalStorage

I am busy working on a "Headless" E-Commmerce Application in ReactJS and I Have stumbled upon an issue regarding performance.
My application uses a serverless approach with commercejs meaning I fetch my products and every other data via API calls instead of a traditional approach that involves me setting up a database and having other backend tools.
I already have this:
const App = () => {
const [products, setProducts ] = useState([]);
const getProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data)
}
useEffect(() => {
getProducts()
},[])
}
Which is all used to get products and assign them to the products variable which I map through to display them inside divs and this works perfectly.
Here's what I need help with:
Is it be a good idea for me to use localStorage to store products instead of making a new commerce.products.list() every time the same user visits a page that need to display products?
Also, if so, how would one go about creating a function that knows when to update the products localStorage if there has been any changes (say a new product has been added or there's been price change for a certain product) if the products are now being fetched from localStorage?
Surely the answer to number 2, if is a yes, will be something like: make api requests that will be called on intervals but my main question/concern is how to know exactly when localStorage should be updated in an event like this without calling the API every now and then?
Also the use of sessionStorage did cross my mind, and it seemed like a better idea as the products data will be updated every time a user visits the application but I have considered the possibility of a user resuming a current window which was left open in the background for weeks and not see anything new.
I know this isn't a typical code/error/solution question but still any form of guidance/assistance will be highly appreciated.

React sending data from one component to another one

This is a function on my Login component page and result.user when user logs in successfully responds with user information. How can I send the result.user information to my main page, so I can set what a user can and can't do?
newLogin = (e) => {
fetch("http://localhost:4000/login", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify(this.state)
})
.then((response) => response.json())
.then((result) => {
console.log(result.user)
});
}
I don't know the structure of your components but You should use react-redux to store your logged-in user because this data is needed to access anywhere in your application and in any component, I highlyl recommend to you to use react-redux for your best practice.
React-redux is easy to use and easy to access any logged-in user's data from the state, so it's better to approach to use react-redux instead of passing data through props.
you can use localStorage to store the data in the browser. in which you can store the data and can use it in anywhere of your code. you don't need to pass the data. when the user log out you need to clear the sorage.
To craete a element in storage
localStorage.setItem('userData', 'result.user')
To clear the data when user logout
localStorage.removeItem('userData');
here userData is representing data stored in the browser.
you can check each time when you needed ,so that whether the user is still logged in using
localStorage.getItem('userData');
if userData is available then you can consider that user is logged in.
Best practice for managing user login in react apps is to use state management for those like Redux and Mobx, you can use React.Context which is easy to use.
In one case I created a wrapper for React.Context.
React-principal
In another case, I created a state management which is so much easier to use react-global-hook

How to save data from API to state in Reactjs?

How can I save my object that is fetched from API in state in such a way that after page refresh it should be still available.How to save fetched data from API to state with parameter name?
As i don't want to save object in local storage or session storage.
This can be helpful in such a way that before fetching to the same API it will check if the object is already there then no fetching is required for that API
Suppose mine API look like https://example.com/new/${numberID}/staff
When first time API is executed for the {numberID} => 12ab1 parameter it should store the result for that {numberID} in state now when {numberID}=> 13ab2 parameter is updated again it should store in new state in such a way
Now {numberID} => 12ab1 parameter called again rather fetching from API it should fetch details from state. this will save my API re- hitting
Is this possible using react-hooks?
This is not possible.
State is maintained for the lifetime of the application. When you refresh the page, you are destroying the current instance of the application and creating a new one, therefore state can not be persisted.
The only way to persist data across a refresh is to use third party software or things like browser storage.
Use localStorage API https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
You can put your data in localStorage and get it from there if you need it. For example
if (!localStorage.getItem('data')) {
axios.get(`https://example.com/new/${numberID}/staff`)
dispatch({
type: "FETCHSUCCESS",
payload: response.data
});
localStorage.setItem('data', response.data);
})
.catch(error => {
dispatch({
type: "FETCHFAILURE"
});
});
}

Redux Offline issue with rehydrating reducer to null

I am using redux-offline, below is how I am creating my store
let customConfig = {
...offlineConfig,
persistOptions:{
key: 'root',
transforms: [immutableTransform()],
},
returnPromises : false,
persistCallback : () => {this.setState({rehydrated : true})}
};
const { middleware, enhanceReducer, enhanceStore } = createOffline(customConfig);
let middlewares = applyMiddleware(offlineCommitHandler,thunk,middleware,);
store = createStore(enhanceReducer(IndexReducer),undefined,compose(enhanceStore,middlewares,persistAutoRehydrate({log:true})));
I have multiple reducers.
The issue occurs only in rehydrating one reducer, for ex : reducerA
I placed a debugger in autoRehydrate
When opening the app first time it merges the data for reducerA
When opening the app second time inbound state for reducerA is
null.
I never did offline config but I ran into similiar problems with redux-persist.
So first of all you want to make sure that your debugger and your device/emulator are not drifting away in time. This would cause me problems all the time, simply restarting the emulator and chrome tab which I was using for debugging would solve it.
Second, you want to check if you don't have any errors in your reducer. In my case, I was not following the immutability pattern and that would sometimes cause redux not to persist my state, as it did not see any difference between the old state and the new state.
For anyone looking for answer to similar issue.
My issue was that the data i was trying to store was hitting the max storage limit for asyncStorage .
https://github.com/rt2zz/redux-persist/issues/199
I had to shift to using filestorage instead of asyncStorage to get redux persist store the data

Resources