window.location.reload is refreshing page again and again - javascript

I am working on project where I am invalidating browser cache but when I call this function window.location.reload() it refresh page again and again . I want to reload page at once . Could someone please help me how to stop page from refreshing again and again . Thanks
Note: I am using React.JS
Code
import React from "react";
import packageJson from "../package.json";
global.appVersion = packageJson.version;
// version from response - first param, local version second param
const semverGreaterThan = (versionA, versionB) => {
const versionsA = versionA.split(/\./g);
const versionsB = versionB.split(/\./g);
while (versionsA.length || versionsB.length) {
const a = Number(versionsA.shift());
const b = Number(versionsB.shift());
// eslint-disable-next-line no-continue
if (a === b) continue;
// eslint-disable-next-line no-restricted-globals
return a > b || isNaN(b);
}
return false;
};
class CacheBuster extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
isLatestVersion: false,
refreshCacheAndReload: (caches) => {
if (caches) {
caches.keys().then(async function (names) {
await Promise.all(names.map((name) => caches.delete(name)));
});
}
window.location.reload();
},
};
}
componentDidMount() {
fetch(`/meta.json?${new Date().getTime()}`, { cache: "no-cache" })
.then((response) => response.json())
.then((meta) => {
const latestVersion = meta.version;
const currentVersion = global.appVersion;
const shouldForceRefresh = semverGreaterThan(
latestVersion,
currentVersion
);
if (shouldForceRefresh) {
console.log(
`We have a new version - ${latestVersion}. Should force refresh`
);
this.setState({ loading: false, isLatestVersion: false });
} else {
console.log(
`You already have the latest version - ${latestVersion}. No cache refresh needed.`
);
this.setState({ loading: false, isLatestVersion: true });
}
});
}
render() {
const { loading, isLatestVersion, refreshCacheAndReload } = this.state;
return this.props.children({
loading,
isLatestVersion,
refreshCacheAndReload,
});
}
}
export default CacheBuster;

if (caches) {...} else (window.location.reload(true));

This code is struck between constructor and the render.
this.state.refreshCacheAndReload should be set to null in constructor, where in you choose to reload it in componentdidmount whenever the version mismatches.

Related

React Native app has low performance while fetching data from firebase

Hello I have a react native app that gets slow/freeze while fetching data from realtime db.
This is only on android devices, on IOs the app works fine.
for example, by using the performance monitor in my physical device I get:
UI: 59 fps
79 DROPEDD
3 Stuters fo far
JS: -2.1 fps
I get the data in the App.js as the following code, which it is inside an useEffect with an empty dependency array:
async function fetchData() {
try {
const [
postFetched,
categoriesFetched,
assetsFetched,
] = await Promise.all([getAllPosts(), getCategories(), getAssets()]);
const email = await AsyncStorage.getItem('#email');
//Alert.alert(`whats uid ? ${email}`);
if (email) {
const userFetched = await searchUserByEmail(email);
setUser(Object.values(userFetched.val())[0]);
}
// eslint-disable-next-line no-undef
const t2 = performance.now();
//Alert.alert(`time ${(t2 - t1) / 1000} seg`);
return {postFetched, categoriesFetched, assetsFetched};
} catch (error) {
throw new Error(error.toString());
}
}
fetchData()
.then((data) => {
const {postFetched, categoriesFetched, assetsFetched} = data;
if (postFetched.exists()) {
setPosts(
orderBy(
toArray(postFetched.val()),
['isTop', 'created'],
['desc', 'desc'],
),
);
//setLoading(false);
}
if (categoriesFetched.exists()) {
setCategories(toArray(categoriesFetched.val()));
}
if (assetsFetched.exists()) {
setAssetsFirebase(assetsFetched.val());
// SplashScreenNative.hide();
}
// SplashScreenNative.hide();
/*if (Platform.OS === 'android') {
setIsLoading(false);
}*/
})
.catch((error) => {
Toast.show({
type: 'error',
text1: 'error ' + error.toString(),
});
console.log('error', error);
});
listenPostsChange(); // -> this also inside the same use effect
the listenPostChange function:
const listenPostsChange = () => {
listenPosts((data) => {
data.exists() &&
setPosts(
orderBy(toArray(data.val()), ['isTop', 'created'], ['desc', 'desc']),
);
});
};
the firebase methods are defined in a separate js file for each reference:
post.js
import database from '#react-native-firebase/database';
const PostsRef = database().ref('/posts');
export const listenPosts = (callbackFunction) => {
return PostsRef.on('value', callbackFunction);
};
export const listenPosts = (callbackFunction) => {
return PostsRef.on('value', callbackFunction);
};
category.js
import database from '#react-native-firebase/database';
const CategoriesRef = database().ref('/categories');
export const addCategory = (label, category) => {
return CategoriesRef.child(label).update({...category});
};
export const getCategories = () => {
return CategoriesRef.once('value', (snapshot) =>
snapshot.exists() ? snapshot.val() : [],
);
};
assets.js
import database from '#react-native-firebase/database';
const AssetsRef = database().ref('/assets');
export const getAssets = () => {
return AssetsRef.once('value', (snapshot) =>
snapshot.exists() ? snapshot.val() : [],
);
};
I have the following dependencies installed in my app:
"#react-native-firebase/app": "^14.2.2",
"#react-native-firebase/auth": "^14.2.2",
"#react-native-firebase/database": "^14.11.0",
"#react-native-firebase/storage": "^14.11.0",
"firebase": "8.10.1",
I think the main problem is related to firebase since when I deleted the fetchData and the listenPostsChange functions, the app worked smoothly but without data to show.
I hope someone can help me
thanks.
edit: I just have like 15 post and 6 categories, and the assets are just 3 strings values.

When routing mswjs/data populates the database with new items and removes the previous one, making it inaccessible

I use next-redux-wrapper, MSW, #mswjs/data and redux-toolkit for storing my data in a store as well as mocking API calls and fetching from a mock Database.
I have the following scenario happening to me.
I am on page /content/editor and in the console and terminal, I can see the data was fetched from the mock database and hydrated from getStaticProps of Editor.js. So now IDs 1 to 6 are inside the store accessible.
Now I click on the PLUS icon to create a new project. I fill out the dialog and press "SAVE". a POST request starts, it's pending and then it gets fulfilled. The new project is now in the mock DB as well as in the store, I can see IDs 1 to 7 now.
Since I clicked "SAVE" and the POST request was successful, I am being routed to /content/editor/7 to view the newly created project.
Now I am on Page [id].js, which also fetched data from the mock DB and then it gets stored and hydrated into the redux store. The idea is, it takes the previous store's state and spreads it into the store, with the new data (if there are any).
Now the ID 7 no longer exists. And IDs 1 to 6 also don't exist anymore, instead, I can see in the console and terminal that IDs 8 to 13 were created, and the previous ones are no more.
Obviously, this is not great. When I create a new project and then switch the route, I should be able to access the newly created project as well as the previously created ones. But instead, they all get overwritten.
It either has something to do with the next-redux-wrapper or MSW, but I am not sure how to make it work. I need help with it. I will post some code now:
Code
getStaticProps
// path example: /content/editor
// Editor.js
export const getStaticProps = wrapper.getStaticProps(
(store) =>
async ({ locale }) => {
const [translation] = await Promise.all([
serverSideTranslations(locale, ['editor', 'common', 'thesis']),
store.dispatch(fetchProjects()),
store.dispatch(fetchBuildingBlocks()),
]);
return {
props: {
...translation,
},
};
}
);
// path example: /content/editor/2
// [id].js
export const getStaticProps = wrapper.getStaticProps(
(store) =>
async ({ locale, params }) => {
const { id } = params;
const [translation] = await Promise.all([
serverSideTranslations(locale, ['editor', 'common', 'thesis']),
store.dispatch(fetchProjects()),
// store.dispatch(fetchProjectById(id)), // issue: fetching by ID returns null
store.dispatch(fetchBuildingBlocks()),
]);
return {
props: {
...translation,
id,
},
};
}
);
Mock Database
Factory
I am going to shorten the code to the relevant bits. I will remove properties for a project, as well es helper functions to generate data.
const asscendingId = (() => {
let id = 1;
return () => id++;
})();
const isDevelopment =
process.env.NODE_ENV === 'development' || process.env.STORYBOOK || false;
export const projectFactory = () => {
return {
id: primaryKey(isDevelopment ? asscendingId : nanoid),
name: String,
// ... other properties
}
};
export const createProject = (data) => {
return {
name: data.name,
createdAt: getUnixTime(new Date()),
...data,
};
};
/**
* Create initial set of tasks
*/
export function generateMockProjects(amount) {
const projects = [];
for (let i = amount; i >= 0; i--) {
const project = createProject({
name: faker.lorem.sentence(faker.datatype.number({ min: 1, max: 5 })),
dueDate: date(),
fontFamily: getRandomFontFamily(),
pageMargins: getRandomPageMargins(),
textAlign: getRandomTextAlign(),
pageNumberPosition: getRandomPageNumberPosition(),
...createWordsCounter(),
});
projects.push(project);
}
return projects;
}
API Handler
I will shorten this one to GET and POST requests only.
import { db } from '../../db';
export const projectsHandlers = (delay = 0) => {
return [
rest.get('https://my.backend/mock/projects', getAllProjects(delay)),
rest.get('https://my.backend/mock/projects/:id', getProjectById(delay)),
rest.get('https://my.backend/mock/projectsNames', getProjectsNames(delay)),
rest.get(
'https://my.backend/mock/projects/name/:id',
getProjectsNamesById(delay)
),
rest.post('https://my.backend/mock/projects', postProject(delay)),
rest.patch(
'https://my.backend/mock/projects/:id',
updateProjectById(delay)
),
];
};
function getAllProjects(delay) {
return (request, response, context) => {
const projects = db.project.getAll();
return response(context.delay(delay), context.json(projects));
};
}
function postProject(delay) {
return (request, response, context) => {
const { body } = request;
if (body.content === 'error') {
return response(
context.delay(delay),
context.status(500),
context.json('Server error saving this project')
);
}
const now = getUnixTime(new Date());
const project = db.project.create({
...body,
createdAt: now,
maxWords: 10_000,
minWords: 7000,
targetWords: 8500,
potentialWords: 1500,
currentWords: 0,
});
return response(context.delay(delay), context.json(project));
};
}
// all handlers
import { buildingBlocksHandlers } from './api/buildingblocks';
import { checklistHandlers } from './api/checklist';
import { paragraphsHandlers } from './api/paragraphs';
import { projectsHandlers } from './api/projects';
import { tasksHandlers } from './api/tasks';
const ARTIFICIAL_DELAY_MS = 2000;
export const handlers = [
...tasksHandlers(ARTIFICIAL_DELAY_MS),
...checklistHandlers(ARTIFICIAL_DELAY_MS),
...projectsHandlers(ARTIFICIAL_DELAY_MS),
...buildingBlocksHandlers(ARTIFICIAL_DELAY_MS),
...paragraphsHandlers(ARTIFICIAL_DELAY_MS),
];
// database
import { factory } from '#mswjs/data';
import {
buildingBlockFactory,
generateMockBuildingBlocks,
} from './factory/buildingblocks.factory';
import {
checklistFactory,
generateMockChecklist,
} from './factory/checklist.factory';
import { paragraphFactory } from './factory/paragraph.factory';
import {
projectFactory,
generateMockProjects,
} from './factory/project.factory';
import { taskFactory, generateMockTasks } from './factory/task.factory';
export const db = factory({
task: taskFactory(),
checklist: checklistFactory(),
project: projectFactory(),
buildingBlock: buildingBlockFactory(),
paragraph: paragraphFactory(),
});
generateMockProjects(5).map((project) => db.project.create(project));
const projectIds = db.project.getAll().map((project) => project.id);
generateMockTasks(20, projectIds).map((task) => db.task.create(task));
generateMockBuildingBlocks(10, projectIds).map((block) =>
db.buildingBlock.create(block)
);
const taskIds = db.task.getAll().map((task) => task.id);
generateMockChecklist(20, taskIds).map((item) => db.checklist.create(item));
Project Slice
I will shorten this one as well to the relevant snippets.
// projects.slice.js
import {
createAsyncThunk,
createEntityAdapter,
createSelector,
createSlice,
current,
} from '#reduxjs/toolkit';
import { client } from 'mocks/client';
import { HYDRATE } from 'next-redux-wrapper';
const projectsAdapter = createEntityAdapter();
const initialState = projectsAdapter.getInitialState({
status: 'idle',
filter: { type: null, value: null },
statuses: {},
});
export const fetchProjects = createAsyncThunk(
'projects/fetchProjects',
async () => {
const response = await client.get('https://my.backend/mock/projects');
return response.data;
}
);
export const saveNewProject = createAsyncThunk(
'projects/saveNewProject',
async (data) => {
const response = await client.post('https://my.backend/mock/projects', {
...data,
});
return response.data;
}
);
export const projectSlice = createSlice({
name: 'projects',
initialState,
reducers: {
// irrelevant reducers....
},
extraReducers: (builder) => {
builder
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.log('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
return {
...state,
...action.payload.projects,
statuses,
};
})
.addCase(fetchProjects.pending, (state, action) => {
state.status = 'loading';
})
.addCase(fetchProjects.fulfilled, (state, action) => {
projectsAdapter.addMany(state, action.payload);
state.status = 'idle';
action.payload.forEach((item) => {
state.statuses[item.id] = 'idle';
});
})
.addCase(saveNewProject.pending, (state, action) => {
console.log('SAVE NEW PROJECT PENDING', action);
})
.addCase(saveNewProject.fulfilled, (state, action) => {
projectsAdapter.addOne(state, action.payload);
console.group('SAVE NEW PROJECT FULFILLED');
console.log(current(state));
console.log(action);
console.groupEnd();
state.statuses[action.payload.id] = 'idle';
})
// other irrelevant reducers...
},
});
This should be all the relevant code. If you have questions, please ask them and I will try to answer them.
I have changed how the state gets hydrated, so I turned this code:
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.log('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
return {
...state,
...action.payload.projects,
statuses,
};
})
Into this code:
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.group('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
state.statuses = { ...state.statuses, ...statuses };
projectsAdapter.upsertMany(state, action.payload.projects.entities);
})
I used the adapter to upsert all entries.

sync button state in realtime using APIs in React Js

So I have two APIs one is Post API Which I linked to my Toggle button, whenever button is clicked it sends 1 or 0 value to Post API and I have other GET API from where I'm getting the state of value which I'm using to the same button to check weather it is 0 or 1.
The problem is my code works but it can't get sync because when I click button it updates state value through post API but previous GET Request Makes it again on previous state. so on render button flickers a couple of times and then get settled. Code is given below. Any solution will be highly appreciated. Thanks in advance.
P.S. on componentDidMount() I'm Calling the GET Request and handleChange is linked to the button
class Test extends React. Component {
constructor(props) {
super(props);
this. State = {
checked: false,
value:bool,
}
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.intervalId = setInterval(()=> this.loadData(), 1000);
this.loadData();
}
componentWillUnmount() {
clearInterval(this.intervalId);
}
async loadData() {
const headers = {
'api-key': 'key',
};
try {
const response = await fetch('url', { headers })
const json = await response.json();
const valueUp = json.data ;
if( valueUp ===1 ) {
this.setState({value: valueUp, checked: true})
}
else if (valueUp === 0) {
this.setState({value: valueUp, checked: false})
}
}
catch (err){ console.log(err);}
}
handleChange() {
if (this.state.value === 0) {
this.setState({ value:1, checked: true }, () => {
this.afterSetStateFinished();
})
}
else if (this.state.value === 1) {
this.setState({ value:0, checked: false }, () => {
this.afterSetStateFinished();
})
}
};
afterSetStateFinished(){
const article = {
"body": this.state.value
}
const headers = {
'api-key': 'key',
};
axios.post('url', article, { headers })
.then(function(response) {console.log(response);
})
}

why componentdidmount called two times

I have React Component in componentDidMount fetch data from the server. The issue is componentDidMount called twice also the API called twice. I have a view increment API like youtube video views increment twice in the database because of twice API calling.
class SingleVideoPlay extends React.Component {
constructor(props) {
super(props);
this.player = React.createRef();
}
state = {
autoPlay: true,
relatedVideos: [],
video: null,
user: null,
comments: [],
commentInput: {
value: '',
touch: false,
error: false
},
following: false,
tab: 'comments'
};
_Mounted = false;
componentDidMount() {
this._Mounted = true;
if (this._Mounted) {
const videoId = this.props.match.params.id;
this.getVideoDetails(videoId);
}
}
componentWillUnmount() {
this._Mounted = false;
try {
clearInterval(this.state.videoInterval);
this.props.videoEditUrl('');
} catch (error) {}
}
captureVideoTime = async () => {
const { video } = this.state;
const result = await updateWatchTime({
id: video._id,
time: 1
});
if (result.status === 200) {
const updateVideo = {
...video,
secondsWatched: video.secondsWatched + 1
};
this.setState({ video: updateVideo });
}
};
videoEnded = () => {
clearInterval(this.state.videoInterval);
};
videoPause = () => {
clearInterval(this.state.videoInterval);
};
loadVideo = () => {
clearInterval(this.state.videoInterval);
};
playingVideo = () => {
const interval = setInterval(this.captureVideoTime, 1000);
this.setState({ videoInterval: interval });
};
getVideoDetails = async (videoId) => {
const video = await getVideo(videoId);
if (video.status === 200) {
let response = video.data;
if (this.props.userId)
if (response.user._id === this.props.userId._id)
this.props.videoEditUrl(`/video/edit/${response.media._id}`);
this.setState({
relatedVideos: response.videos.docs,
video: response.media,
user: response.user
});
this.checkIsFollowing();
this.updateVideoStat(response.media._id);
}
};
updateVideoStat = async (id) => videoView(id);
checkIsFollowing = async () => {
const { userId } = this.props;
const { video } = this.state;
if (userId && video) {
const response = await isFollow({
follower: userId._id,
following: video._id
});
if (response) {
this.setState({ following: response.following });
}
}
};
addOrRemoveFollowing = async () => {
this.checkIsFollowing();
const { following, video } = this.state;
const { userId } = this.props;
if (userId) {
if (following) {
const response = await removeFollow({
follower: userId._id,
following: video._id
});
this.setState({ following: false });
} else {
const response = await addFollow({
follower: userId._id,
following: video._id
});
this.setState({ following: true });
}
}
};
submitCommentHandler = async (event) => {
const { userId } = this.props;
event.preventDefault();
if (userId) {
const result = await saveComment({
mediaId: this.state.video._id,
parentId: '0',
userID: userId._id,
userName: userId.username,
comment: this.state.commentInput.value
});
console.log(result);
if (result.status === 200) {
this.getVideoComments();
this.setState({ commentInput: { value: '', touch: false, error: false } });
}
}
};
render() {
const { autoPlay, relatedVideos, video, user, comments, commentInput, following, tab } = this.state;
const { userId } = this.props;
return (
<div className="container-fluid">
some coponents
</div>
);
}
}
const mapStateToProps = (state) => ({
userId: state.auth.user
});
export default connect(mapStateToProps, { videoEditUrl })(SingleVideoPlay);
I don't know why componentDidMount called two times alse it shows memmory lecage issue.
How to Fix it.
Multiple componentDidMount calls may be caused by using <React.StrictMode> around your component. After removing it double calls are gone.
This is intended behavior to help detect unexpected side effects. You can read more about it in the docs. It happens only in development environment, while in production componentDidMount is called only once even with <React.StrictMode>.
This was tested with React 18.1.0
I think the issue exists on the parent component that used SingleVideoPlay component. Probably that parent component caused SingleVideoPlay component rendered more than once.
Also, there is an issue on your code.
componentDidMount() {
this._Mounted = true;
if (this._Mounted) {
const videoId = this.props.match.params.id;
this.getVideoDetails(videoId);
}
}
Here, no need to check if this._Mounted, because it will always be true.
1.Install jQuery by
npm i jquery
import $ from 'jquery'
create your function or jwuery code after the export command or put at the end of the file

Javascript function first execute and return value, before proceedng

I am writing a React application where I first want to make sure that both of my JWT token are set prior continuing the application (componentDidMount lifecycle hook). I used a callback to make certain that the second function awaits the first function. but for some reason the value is not in my localstorage yet. I cannot use redux for this, as the first two calls that I am fetching are user images.
All hints/advise is welcome. Thanks.
app.js
componentWillMount() {
function firstFunction(_callback){
acquireToken();
acquireGraphToken();
_callback();
}
function secondFunction(){
firstFunction(function() {
console.log('huzzah, I\'m done!');
});
}
secondFunction();
}
ADAL.JS (Which handles my token requests.)
import { AuthenticationContext, adalFetch } from 'react-adal';
const adalConfig = {
instance: 'https://login.microsoftonline.com/',
clientId: '*******',
extraQueryParameter: 'nux=1',
endpoints: {
graphApi: 'https://graph.microsoft.com',
oneApi: 'https://one365demo.onmicrosoft.com/b153b2*********-3f1d0cf658f5'
},
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
export const authContext = new AuthenticationContext(adalConfig);
export const adalGraphFetch = (fetch, url, options) =>
adalFetch(authContext, adalConfig.endpoints.graphApi, fetch, url, options);
export const adalOneApiFetch = (fetch, url, options) =>
adalFetch(authContext, adalConfig.endpoints.oneApi, fetch, url, options);
export const getToken = () => {
return authContext.getCachedToken(authContext.config.clientId);
};
export const getGraphToken = () => {
return authContext.getCachedToken('https://graph.microsoft.com');
};
export const acquireGraphToken = () => {
authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => {
console.log('graph token', token);
return token;
})
return null;
}
export const acquireToken = () => {
authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => {
console.log('the token', token);
return token;
})
return null;
}
The render() method evaluates once in a very early moment, before componentWillMount(). Then it is reevaluated (in principle) every time the component state is changed via the setState method.
What I usually do is to mark in the component's state when the initialization is completed, and check for this mark in the render() method. In your example:
componentWillMount() {
function firstFunction(_callback){
acquireToken();
acquireGraphToken();
_callback();
}
function secondFunction(){
firstFunction(function() {
console.log('huzzah, I\'m done!');
this.setState({dataIsReady: true})
});
}
secondFunction();
}
render() {
if (this.state.dataIsReady) {
// render the actual app
} else {
// render some "Loading ..." message
}
}
Hope it helps - Carlos
You should create a value in the state to track your preliminary function completion. Just change the value, and then have the component load as normal.
e.g.
class App extends React.Component {
state = { shouldLoad: false }
firstFunction() {
//Execute your functions here then...
//Set state when complete...
this.setState({ shouldLoad: true });
}
render() {
const {shouldLoad} = this.state;
return (
<div>
{shouldLoad === true && (
<p>Load your content here</p>
)}
</div>
);
}
}

Categories

Resources