Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I made a small app using react and it works smoothly on my computer. However, when I open it on different mobile devices it crashes after a minute or so of usage. I don't know what causes the problem but weirdly enough I don't have any bugs or warnings on my console and haven't used componentDidUpdate or hooks that might cause infinite loops like useEffect. Please help me if you know what causes a react app to glitch on mobile devices or have encountered the same problem and found a solution for it.
Here's the app
https://summerresort.netlify.app
and the code
https://github.com/Mahmoud-farargy/summerresort/tree/master/Beach-Resort
Thanks!
Your app looks all ok except 2 points. I can't test my guess, but I'm almost entirely sure that your problem comes from those 2.
Both parts that seem problematic are located in index.js, here there are:
window.addEventListener("scroll", () => {// gets the current height
let scroll = document.body.scrollTop || document.documentElement.scrollTop;
let arrowUp = document.querySelector(".arrow-up-btn").style;
scroll >= 1000 ? arrowUp.display="flex" : arrowUp.display = "none";
});
window.addEventListener("resize", ()=> {// gets the current width
this.setState({
currentPageWidth: window.innerWidth || document.documentElement.clientWidth
})
});
The first code block is expensive because:
The scroll event is fired very frequently.
You don't listen for scroll passively (it'd be a good idea though).
You set the style much more frequently than needed.
However, I think, that it is the second code block that causes mobiles to glitch.
Check out this answer to see why the resize event is fired on mobiles more frequently than on desktop.
Now, each time the resize event is triggered, the state of MainApp
is updated.
Each time MainApp is updated, React recalculates all its children.
By default, React just re-run render of each child & compares the output.
Considering you have all routes & all components inside the MainApp & you didn't implement any optimizations (React.PureComponent, lazy loading for routes, etc.) React will have to recalculate what the entire site looks like on each resize event.
The easiest fix would be to store currentPageWidth in a ref instead of state.
Another possible problem is that by attaching listeners inside the render method, you're attaching new listeners on each single render without clearing any of previously added listeners.
Related
Live example https://snack.expo.dev/su1-U5DZc
If I swipe screens with buttons - everything okay, but if I swipe with gesture - screens shows twice. Why so? Does this setWtf(state.index);
const onTouchStart = (e, state, context) => {
console.log('onTouchStart: ' + state.index);
setWtf(state.index);
};
make index stored somewhere by reference and then get updated?
Yes it was due to setWtf(state.index);. There is a reported bug of render issue when updating state in their official git page.
They are saying to downgrade react-native-swiper to version 1.5.5
or you could follow other solutions mentioned here : Update the state breaks the slides
Without more information, it's impossible to pinpoint the exact cause of the problem you're experiencing, although it's conceivable that the problem is connected to the way your code handles touch events.
Your code is probably adjusting the value of state.index depending on the gesture when you swipe between screens, and then refreshing the screen display based on the value of state.index. The screen display may update twice if state.index is being updated by reference because the value is being modified twice: once by the gesture and once by the setWtf function.
Using a different variable to hold the current screen index and only updating the value of state.index when the user interacts with the buttons is one potential fix for this problem. This should prevent the screen from being displayed more than once and ensure that the value of state.index is only modified once.
It's important to keep in mind that the setWtf function you specified in your query could not be connected to the problem you're having. Without more information, it's difficult to say for sure whether this function is being used to update another state in your application.
I want to use some transition effects in my react js app. I am using function components in my app.
How do I include transition effects in app according to the business requirement these days?
I want to use animation such that on every render I can see the effect. It would be great if someone can help me out with an example.
If you want to use a library, I would suggest react-spring
https://react-spring.io/ it is based on spring physics, If you want to read about that more check this out https://www.joshwcomeau.com/animation/a-friendly-introduction-to-spring-physics/
And there is also another good option which is framer motion https://www.framer.com/motion/ which apparently offers more possibilities maybe out of the box (I personally have never tried it before)
For examples you can check their websites they have good examples.
I'm not sure what effect you are trying to generate.
css can be used by itself to generate animations or transitions.
You want to see the effect on each render?
i.e. You want to tie the effect to the react render cycle?
non-memoized values will change on every render
You could use a simple statement like const trigger = {};
Then react to trigger with a useEffect
useEffect(() => { do something }, [trigger]);
finally, visual effect.. apply a class based on state and use setTimeout to remove the state (and therefore the class)
This could be overly involved for exactly what you are trying to achieve but this works for all possible flows based on the question.
Here is one example with div element is moving to according vertical scroll position .
Look carefully.
First, Set the position using useState and define the window.onscroll function.
const [cardTop, setCardTop] = useState(0);
window.onscroll = function() {
if (window.pageYOffset < 30) {
setCardTop(window.pageYOffset + 'px');
}
};
Second, Set the style's top as state variable.
<div className='card t-card' id='tCard' style={{top:`${cardTop}`}}> ...
Congratulations. It probably act exactly.
It's similar to use Jquery or another Javascript, Only use state variable.
Thanks.
I am using React-admin for a project where for some resources, I use the tabbed form to better organize the fields and inputs. I created a fairly simple custom map component based on react-leaflet, which I am using in these tabbed forms.
I am facing a weird issue where when the map is on other than the first tab, its contents do not display correctly. It appears as though the map "thinks" the viewport is much smaller than it actually is. Reloading the page (or even just opening developer tools in Chrome) forces re-render of the page and causes the map to start behaving correctly.
To better demonstrate, I created this simple Codesandbox project. It has a user resource from the RA tutorial with two tabs. Both contain an instance of the map component, but while the map on the first tab works correctly right away, the one on the second tab renders incorrectly.
I confess I am still kind of a noob at these things so I may well be doing something wrong, but I've been scratching my head for quite a few hours over this and I'd like to start eliminating possible culprits.
Any insight would be most welcome.
Thanks very much in advance for your time.
This issue has been discussed a lot in SO. If you search a bit you can find the reason. What you actually need to do is two things:
use setInterval in combination with map's invalidateSize method when switching a tab and then clean it on component unmount
use useEffect to change mapZoom and view since they are immutable.
SO since you use react-leaflet version 2.7.x you need to take the map instance using a ref:
const mapRef = useRef();
useEffect(() => {
if (!mapRef.current) return;
const map = mapRef.current.leafletElement;
const mapZoom = zoom || defaultZoom;
let intervalInstance;
if (!center && marker) {
map.setView(marker, mapZoom);
intervalInstance = setInterval(() => map.invalidateSize(), 100);
} else if (!center) {
map.setView([0.0, 0.0], mapZoom);
}
map.setZoom(mapZoom);
return () => clearInterval(intervalInstance);
}, []);
<LeafletMap
ref={mapRef}
center={marker}
zoom={defaultZoom}
className={classes.leafletContainer}
>
Demo
I have the following code to perform a state update every time the map move.
function updateMap() {
const b = mapRef.current.leafletElement.getBounds()
const zoomm = mapRef.current.leafletElement.getZoom()
const initBound = [b.getSouthWest().lng, b.getSouthWest().lat, b.getNorthEast().lng, b.getNorthEast().lat]
setZoom(zoomm)
setBound(initBound)
}
bellow is the Map Component, I also tried the onMoveEnd event
<Map onViewportChanged={updateMap}/>
it is working fine for couple of moves however sometime especially if I kept moving the map it freezes and I get the Maximum update depth exceeded error .
can someone please explain the reason, is it a bug on react Leaflet or am I doing something wrong?
You get that error because you're updating state on every move, and in react you can update the state just for a limited number of times to prevent infinite loops for example.
One way to solve the problem is to debounce the updateMap method.
Check this link to look at different ways of performing the debouncing.
I hope this helps!
CodeSandbox with Unit Tests
The CodeSandbox above contains a small code segment that shows the problem. The rendered table contains a bit of data. Everything on the left side is rendered and around the center, #testing-library/react stops rendering anything.
Visually, everything is fine. But the HTML rendered by #testing-library/react misses the entire right half of the table.
You can even see this if you hard reload the tab with CodeSandbox in it, then navigate to the "Browser" tab. The right half will be missing. Click the Browser refresh button in CodeSandbox and everything will be rendered just fine.
Without VirtualTable, everything renders perfectly. However, I need VirtualTable for performance reasons.
Extending the viewport programmatically doesn't help.
// setupTests.js
global.resizeWindow = (x, y) => {
window.innerWidth = x
window.innerHeight = y
window.dispatchEvent(new Event('resize'))
}
// In the test
global.resizeWindow(4096, 2160)
// Same result, no change
Is there any way to keep the benefits of VirtualTable while still running tests on the data contained on the right side of the table?
Here's the response from DevExpress:
Hi,
Thank you for your sample. I have discussed this behavior with our
developers and we concluded that this is the expected behavior. The
VirtualTable plugin renders only visual parts of the Grid control. So,
we recommend that you use the Table plugin for tests and the
VirtualTable plugin in a real application.
Thanks, Alessandro
So it would appear that since we don't have a real browser, the VirtualTable sees no need to render anything.
The solution would be to render a regular Table in a testing scenario, and a VirtualTable in a real-world scenario.
function areWeTestingWithJest() {
return process.env.JEST_WORKER_ID !== undefined;
}
However, using testing code in production code is usually considered bad practice, so I'll just avoid testing VirtualTables and test the data in other places instead.