Using next.js with SSR I'm having a strange problem.
My website renders as expected server-side and is served to the client with styles. There are no surprises here when I'm visiting the website on a laptop everything looks as expected.
However, when I visit the website on a mobile device (or simulated smaller window), the first render is rendered with the same styles as my desktop styles, even though my mobile media query returns true
I'm using https://github.com/wintercounter/use-breakpoint for most of my media queries.
Which looks like this:
const { 'isMobile-': isMobileMinus } = useBreakpoint()
and my layouts etc. should change based on whether isMobileMinus is true or false.
For example, this antD component is supposed to switch from horizontal to vertical if it's a mobile device.
<Space size="middle" direction={isMobileMinus ? 'vertical' : 'horizontal'}>
What is really interesting is that when I render the webpage in a small window the size of a mobile device I can console log isMobileMinus to be true, but my components do not update until I either resize the window (and it's true again) or I navigate to another page and back.
It acts as if isMobileMinus was false, but only for that specific component.
I can even render the value of isMobileMinus in the component and it will render true on first render, but the components I have acts as if it was false until I make another update.
I find this very strange as the component is clearly re-rendering with the correct value, but it does not update the styles of the components that were styled via SSR?
This problem is not just limited to the above hook based media queries but also other things.
For example I have 2 buttons that are rendered on SSR called "login" and "Signup" which are supposed to be white and green respectively.
However when the webpage renders if the user is already logged in. It should render 2 new buttons called "Log out" and "Dashboard" which are red and blue respectively.
But somehow on first render. The text of these buttons will update to logout and dashboard, but the styles of the buttons will be white and green (incorrect).
These are completely different components, but next.js still keeps the old styles?
if (loggedIn) {
return (
<Space>
<LogoutButton onClick={handleLogout} />
<DashboardButton onClick={handleDashboardClick} />
</Space>
)
}
return (
<Space>
<LoginButton />
<SignupButton onClick={showSignup} />
</Space>
)
There seems to be some really strange thing with next.js where it will update the content of the HTML, but refuses to update the CSS when a component is re-rendered on the client-side.
Anyone knows how to fix this?
I tried making a copy like suggested here: How to immediately re-render client-side using React + NextJS after initial server-side render? which seems to be a similar issue.
const breakpoints = useBreakpoint()
const copy = lodash.cloneDeep(breakpoints)
const { 'isMobile-': isMobileMinus } = copy
console.log('🔈 ~ isMobileMinus', isMobileMinus)
But that did not work for me either.
I'm on "next": "11.0.1",
I found 1 solution but it feels more like a hack than a solution.
If I wrap my components in process.browser && (<Component />) then the component will not render during SSR, and only render client-side.
This causes the component to render correctly when the webpage is loaded.
But of course I would ideally like to take advantage of SSR, and just update the styles client side :(
Note that this hack also causes console errors, so it is definitely not recommended. It seems like the use-breakpoint library is incompatible with SSR frameworks.
Related
I have implemented a dark mode to a WordPress site using a simple technique like this one found in https://github.com/avecNava/dark-mode.
<script>
//runs on every page load, checks local storage for last mode and applies dark mode if found
document.body.classList.toggle('dark-mode', localStorage.getItem('darkmode') === 'true');
//the function must be called when dark mode is clicked by the user
function switch_mode(){
const dark = localStorage.getItem('darkmode') === 'true';
localStorage.setItem('darkmode', !dark);
const element = document.body;
element.classList.toggle('dark-mode', !dark);
}
To prevent flickering I've tried to place the first row inside the head tags (via header and footer scripts plugin) but it doesn't seem to work. I've seen solutions to this problem but they all seem to be built different from the start so it's hard to apply those solutions to the code I'm using.
To trigger the switch, I'm using a clickable icon that has an onClick() property that calls the function. Is there any solution to my problem or should I just start the whole thing from scratch using a different technique for example a checkbox trigger?
I have a react component that is rendered in two different pages and I want it to have different css for each page. So I passed it a prop to switch between the css classes, but, because there is no page refresh between the 2 pages, my component doesn't change the css class, only if I manually refresh the page, my component sees the prop I passed and changes the css class.
Can anyone tell me how can I make the component rerender on page change ? even if there is no page refresh?
I tried, until now, to change the state of the component with componentDidUpdate, but it ends up rerendering on a infinite loop, and the page doesn't load anymore.
Is there any other way to do this ?
I think you can solve the problem using history. This will help you to track the URL changes.
if you're using a functional component you can use useParams
the second solution that comes to my mind is to use the param as the key of the component, that will force the re-render.
I imagine you are using react router dom, if so I think getting the location by doing useLocation() would achieve the desired result as when the url changes this hook would cause a re-render
const location = useLocation()
I have a modal dialog in my template. This dialog needs to be triggered from the code programatically. So I need to show the modal through javascript, as I cannot have a data-toggle button to launch the modal-dialog.
The modal was working with bootstrap but with bootstrap-3 its not showing up, even though I can show it from the console directly. the problem here is how can I execute javascript post the template render, to launch the modal-dialog.
There is a Template.rendered/created function which is called, and inside this this.autorun(runFunc) is supposed to run the code to update the DOM element. This is called correctly, but I still cannot trigger the modal to show-up.
Template.createDialog.created = function() {
console.log("teamplate created");
this.autorun(function(){
$('#myModal').modal('show');
});
};
Update:
This works:
Template.createDialog.rendered = function() {
console.log("teamplate created");
this.autorun(function(){
$('#myModal').modal('show');
});
};
Using the rendered function, I am able to trigger the modal to show up. But the problem is that rendered and created both are only called once. And I need a way to trigger the modal dialog consistently if a condition is reached.
This bootstrap modal dialog with meteor is turning out to be painful and hacky. Is it not possible to show/hide modal using some class parameters?
Modals can be tricky to get right in Meteor for exactly the reasons you've discovered. I don't use Bootstrap, but the basic principle is that you need to trigger the modal programatically so that you can run the relevant framework code once you know the html has been rendered but still retain reactivity (this is certainly the case with Foundation and Semantic-UI modals) .
In your use case (which appears to be a single modal), this shouldn't be too much of a problem. Set a reactive variable modalVisible (a Session variable or similar), and use that to show or hide the modal as required.
this.autorun(function(c) {
if (Session.get('modalVisible')) {
$('#myModal').modal('show');
} else {
$('#myModal').modal('hide');
}
});
If you put all of that in the rendered callback then it will only try to show the modal once it's been added to the DOM (without which you'll get an error and the computation will stop running, breaking reactivity). Note that you shouldn't make rendering of the template dependent on a reactive variable - it should always be rendered but only visible based on the value of the modalVisible Session variable.
Apologies if this is too simple for your use case - if so I would recommend investigating the several packages on Atmosphere for Bootstrap modals as others will almost certainly have faced the same problem.
i have an webapp and i need to onclick change css style, but i need to save this change in the webapp instaled into the phone of my user, and only in his phone. The javascript for onclick change css style it's working but i don't have no idea to how to save this css changes.
Can somebody help me with this?
Since now thanks
In general CSS styles can't be directly saved on an HTML client.
What you can do is make an Ajax call back to your server and save the information there. The next time the user asks for the page send HTML with the appropriate style class already on the element you wish to style based on the saved information.
There are several hackish client side possibilities involving JavaScript & cookies or local storage but I would avoid that sort of solution if at all possible since it's very likely to lead to an annoying flicker as the page loads and renders styled one way and then the JavaScript finally runs and corrects the style.
To elaborate on my comment:
el1.addEventListener('click', function() {
el2.style.color = 'red';
localStorage['color'] = el2.style.color;
})
And then on startup:
window.addEventListener('load', function() {
if (localStorage['color']) {
el2.style.color = localStorage['color'];
}
}
Of course, you may want to add error checking and fallbacks as appropriate.
I have rather a complex UI. However, for the purpose of this question, let's say that there is a HTML table that renders UILayout1 by default (say default mode). There is a button that a user can use to toggle between the default mode and a preview mode (UILayout2)
When in preview mode, there are some columns in the table that are invisible and there are reordering of rows. I am using JS (jquery) on load to check the mode and change it accordingly.
The table and the toggle button are in UpdatePanels.
Functionally, everything works as expected. However, when a user toggles between default and preview mode or vice versa, there is this short time interval in which the the table renders in default and then JS runs to make changes.
This results in degraded UI experience. Are there any creative ways to avoid this "flicker"?
you can use DIVs or don't use update panel in your UI generation use any concept else
The problem is likely to be that your code is running on load. I'm assuming that you're doing this using the standard jQuery method of running code on load, and not using the window's onload event. In any case, even using jQuerys $(document).ready(...) will be too slow if you have a lot of other javascript files to load, as the .ready event isn't fired on the document until all javascript includes have loaded.
You should be able to work around the issue by including your code that modifies the table just after the html for the table in your page and not running it on load i.e. make sure you don't wrap it in $(document).ready(...);
For this approach to work, you will need to have all javascript required by the code which is modifying the table included earlier in the page.
If you have other non-essential javascript files included, you should try to include them later in the page.
I'm not 100% sure how being inside an update panel will affect it - you will need to make sure that your code is being re-triggered when the updatepanel updates, but I believe this should all happen automatically.
Presumably your UI is controlled by CSS? You might be able to get rid of the flickering by adding something like this at the start of your JavaScript or in the <head> of your HTML:
if (previewMode) {
document.documentElement.className = 'preview';
}
Then if you modify your CSS rules that apply to your preview mode to reflect the HTML element having the class="preview" to something like:
.preview table .defaultMode {
display:none;
}
hopefully your table should render correctly first time and will not need to be re-drawn.