When i operate infinity scroll in the mobile view, the scroll goes to the top - reactjs

I'm using IntersectionObserver to implement an infinite scroll.
It works well in desktop view, but in mobile view, the scroll moves to the top whenever the isVisible of the source code below changes.
This is not what I want to do.
const targetRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries: IntersectionObserverEntry[]) => {
if (entries[0].isIntersecting) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, {
root: null,
rootMargin: '1px',
threshold: 0.1,
});
targetRef.current && observer.observe(targetRef.current);
return () => {
observer.disconnect();
};
}, []);
useEffect(() => {
if (!isVisible || cursor === null) return;
dispatch(getDrawings({ userId: Number(profileId), cursor: cursor }))
.unwrap()
.then((res) => {
const { newCursor } = res;
console.log({ newCursor });
setCursor(newCursor);
});
}, [isVisible]);
Can you help me solve this problem?

Related

Enable a listener when an application is started or in the foreground

With react-native, AppState component allows to listen if an application is in the foreground (active) or in the background (background).
Its implementation is very simple :
useEffect(() => {
const appStateListener = AppState.addEventListener('change', appState => {
if (appState === 'active') {
console.log('App active')
} else {
console.log('App not active')
}
// !!!!! no console.log() at application startup, only when changing background/foreground !!!!!
})
return () => appStateListener.remove()
}, [])
react-native-mmkv allows to store values locally. It has a listener to detect changes :
useEffect(() => {
const storageListener = storage.addOnValueChangedListener((changedKey) => {
const newValue = storage.getString(changedKey)
console.log(`"${changedKey}" new value: ${newValue}`)
})
return () => storageListener.remove()
}, [])
But I don't know how to use both simultaneously. I would like to activate the react-native-mmkv listener when the application starts (useEffect()) AND when the application is in the foreground.
When the application is closed or in the background, I would like to remove this listener.
I tried this but I know it's not good, and the application crashes when the application goes from the background to the foreground ("Maximum call stack size exceeded").
useEffect(() => {
const enableStorageListener = () => {
return storage.addOnValueChangedListener((changedKey) => {
//...
})
}
let storageListener = enableStorageListener()
const appStateListener = AppState.addEventListener('change', appState => {
if (appState === 'active') {
storageListener = enableStorageListener()
} else {
storageListener.remove()
}
})
return () => {
appStateListener.remove()
storageListener.remove()
}
}, [])
Can you try to keep the AppState in a state
const [appState, setAppState] = useState("");
useEffect(() => {
const appStateListener = AppState.addEventListener("change", (appState) => {
if (appState === "active") {
setAppState("active");
console.log("App active");
} else {
setAppState("deactive");
console.log("App not active");
}
// !!!!! no console.log() at application startup, only when changing background/foreground !!!!!
});
return () => appStateListener.remove();
}, []);
useEffect(() => {
const storageListener = storage.addOnValueChangedListener((changedKey) => {
if (appState === "active") {
const newValue = storage.getString(changedKey);
console.log(`"${changedKey}" new value: ${newValue}`);
}
});
return () => storageListener.remove();
}, []);
To use both components, you can combine their listeners within a single useEffect hook, and conditionally enable/disable the storage listener based on the app state:
useEffect(() => {
let storageListener = null;
const enableStorageListener = () => {
storageListener = storage.addOnValueChangedListener((changedKey) => {
// ...
});
};
const appStateListener = AppState.addEventListener('change', (appState) => {
if (appState === 'active') {
enableStorageListener();
} else if (storageListener) {
storageListener.remove();
storageListener = null;
}
});
if (AppState.currentState === 'active') {
enableStorageListener();
}
return () => {
appStateListener.remove();
if (storageListener) {
storageListener.remove();
}
};
}, []);
This way, the storage listener is enabled when the app is active and disabled when it's in the background. The return statement in the hook is used to cleanup the listeners when the component is unmounted.

react infinite scroll with IntersectionObserver not working

I don't know why the infinite scroll made of react doesn't work.
Here's what I think.
Connected Element Detection
isFetching = true
setTest()
const [isFetching, setIsFetching] = useState(false);
useEffect(() => {
const io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsFetching(true);
}
});
setIsFetching(false);
});
io.observe(document.getElementById("finish")!);
return () => io.disconnect();
}, []);
useEffect(() => {
if (!isFetching) return;
setTest([...test, 1]);
}, [isFetching, test]);```

React Context - fix unecessary rerenders - eslint issue

Eslint throw error:
The object passed as the value prop to the Context provider (at line
147) changes every render. To fix this consider wrapping it in a
useMemo hook
I have all my functions in callbacks, and also use a bit of useMemo however I sort of have no clue how to proceed with others to make my context clean and highly performance without unecessary rerenders, Would be grateful if someone could take a look and see how can it be improved to make error disappear and context work fine
const MapProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
const [coordinates, setCoordinates] = useState<LatLngType>({ lat: 9.05789, lng: 29.92313 });
const [activeMarker, setActiveMarker] = useState<string>('');
const [directions, setDirection] = useState<DirectionResults>();
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS ?? ''
});
const mapRef = useRef<MapType>();
const options = useMemo<MapOptionsType>(() => {
return {
disableDefaultUI: false,
clickableIcons: false
};
}, []);
const onLoad = useCallback((map: MapType) => {
mapRef.current = map;
}, []);
const getCurrentPosition = useCallback(async () => {
try {
const coord = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });
setCoordinates({
lat: coord.coords.latitude,
lng: coord.coords.longitude
});
} catch (error) {
console.log(error);
}
}, []);
const watchUserPosition = useCallback(async () => {
const watchOptions = { timeout: 60000 };
const showLocation = (position: Position | null, err?: any): void => {
if (err) return console.error('Map was not loaded', err);
if (position) {
const {
coords: { latitude, longitude }
} = position;
setCoordinates({
lat: latitude,
lng: longitude
});
}
};
await Geolocation.watchPosition(watchOptions, showLocation);
}, []);
useEffect(() => {
getCurrentPosition();
watchUserPosition();
}, []);
const moveToMarkerLocation = useCallback(
(marker_coordinates: LatLngType) => {
mapRef.current?.panTo(marker_coordinates);
},
[mapRef.current]
);
const openMarker = useCallback((marker: string) => {
setActiveMarker(marker);
}, []);
const closeMarker = useCallback(() => {
setActiveMarker('');
}, []);
const showDirection = useCallback(
(marker_position: LatLngType) => {
const service = new window.google.maps.DirectionsService();
service.route(
{
origin: coordinates,
destination: marker_position,
travelMode: window.google.maps.TravelMode.WALKING
},
(result, status) => {
if (status === 'OK' && result) {
setDirection(result);
}
}
);
},
[coordinates]
);
const endDirection = useCallback(() => {
setDirection(undefined);
}, []);
return (
<MapContext.Provider
value={{
isLoaded,
mapRef,
moveToMarkerLocation,
coordinates,
options,
onLoad,
openMarker,
closeMarker,
activeMarker,
directions,
showDirection,
endDirection
}}>
{children}
</MapContext.Provider>
);
};
Way to make error disappear is :
const mapValues = useMemo(
() => ({
isLoaded,
mapRef,
moveToMarkerLocation,
coordinates,
options,
onLoad,
openMarker,
closeMarker,
activeMarker,
directions,
showDirection,
endDirection
}),
[
isLoaded,
mapRef,
moveToMarkerLocation,
coordinates,
options,
onLoad,
openMarker,
closeMarker,
activeMarker,
directions,
showDirection,
endDirection
]
);
return <MapContext.Provider value={mapValues}>{children}</MapContext.Provider>;
But I'm not convinced if it solve the problem with performance eventho eslint error is gone

Electron webcontents.send does not work in production

I have an electron react app where I am trying to communicate between two renderer processes, I managed to get it to work on the dev server but it does not work in production.
Main Process:
ipcMain.on('pass-info', async (event, args: any) => {
console.log('pass-info', args);
const childWindow = createWindow('child', {
width: 1000,
height: 600,
show: false,
});
if (!isProd) {
const prodPath = path.join(__dirname, '../app/test.html');
// await childWindow.loadURL(`file://${prodPath}`);
await childWindow.loadFile(prodPath);
childWindow.show();
} else {
const port = process.argv[2];
await childWindow.loadURL(`http://localhost:${port}/test`);
childWindow.webContents.openDevTools();
childWindow.show();
}
const id = setTimeout(() => {
childWindow.webContents.send('pass-info-response', args);
}, 2000);
return () => clearTimeout(id);
});
I also tried this instead of the setTimeout way
childWindow.webContents.on('did-finish-load', () => {
childWindow.webContents.send('pass-info-response', args);
});
And here is my React page:
const Test = () => {
const [amount, setAmount] = useState('');
React.useEffect(() => {
window.electronAPI.passInfoResponse((event, data) => {
// alert(data);
console.log(data);
setAmount(data.amount);
});
}, []);
return (
<div>
<h1>Test</h1>
{!!amount ? <div>{amount}</div> : <div>Loading...</div>}
</div>
);
};

Set scroll start position in react hooks

I want to make scroll only in chosen place.Before that it have to be impossible scroll the website.
const [doStart] = useState({
startScroll: false
});
useLayoutEffect(() => {
const onScroll = () => {
const scrollPos = window.pageYOffset;
if ( scrollPos === 1000) {
doStart(state => ({ ...state, startScroll: true, }));
}
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [])

Resources