Mithril component not updating when route changes - javascript

I am creating my personal website/blog as a a single page application using Mithril.js. All pages and blog posts on my website are rendered using Page and Post components, and the correct page is loaded based on the :slug in the URL.
The problem I have is that whenever I try and switch between pages, the content of the page does not update. Switching between pages and posts works because I am alternating between Page and Post components. But when I try and use the same component twice in a row, going from page to page, it doesn't update the webpage.
m.route(document.body, '/', {
// `Home` is a wrapper around `Page`
// so I can route to `/` instead of `/home`
'/': Home,
'/:slug': Page,
'/blog/:slug': Post
});
const Home = {
view() {
return m(Page, { slug: 'home' });
}
};
Here is the Page component (the Post component is very similar). Both components render correctly.
const Page = {
content: {},
oninit(vnode) {
m.request({
method: 'GET',
url: 'content.json',
}).then((response) => {
Page.content = response.pages[vnode.attrs.slug];
});
},
view() {
if (Page.content) {
return [
m('#content', m.trust(Page.content.body))
];
}
}
};
Why isn't Mithril recognizing that the slug changed?

The docs page for m.route has a solution for you.
When a user navigates from a parameterized route to the same route with a different parameter (e.g. going from /page/1 to /page/2 given a route /page/:id, the component would not be recreated from scratch since both routes resolve to the same component, and thus result in a virtual dom in-place diff. This has the side-effect of triggering the onupdate hook, rather than oninit/oncreate. However, it's relatively common for a developer to want to synchronize the recreation of the component to the route change event.

Related

Router.push or Link not rendering/refreshing the page even thought the url is updated nextjs

I apologize for my horrendous way of explaining my issue. I have shared a link below description which is exactly the same issue I am experiencing. Any kind of help would be greatly appreciated.
I have directory path like pages/request/[reqid].js . When my url is localhost:3000/xyz and I navigate to pages/request/1 by clicking a button on the current page, the page successfully loads the page with proper data from [reqid=1] but when I try to access pages/request/[reqid].js with different reqid (say suppose reqid=2), the url reflects the correct the reqid pages/request/2 but the page remains the same, doesn't change. However if I go back to other pages like localhost:3000/xyz and click a button there to navigate to pages/request/2 it works but from within pages/request/[reqid] it doesn't render a page associated to the corresponding reqid even thought the url is updated. I have tried both Link and router.push ,both fails to render the correct reqid page.
https://github.com/vercel/next.js/issues/26270
It actually failed to include that I was using getServerProps to fetch the data, which was the reason the page wasn't rendering , unless the page was manually refreshed. The page state is not reset for navigation between dynamic routes that served by the same source component.
for example, give page source /a/[param]/index.js, when navigating from /test/123 to /test/124, states on the page wasn't being reset.
So actually happened is the same React Component been rendered with different props. Thus react takes it as a component is rerendering itself, and causing the new navigated page receive stale states.
To fix it, just add {key: } to page initial props or getserversideprops
export const getServerSideProps = async (ctx) => {
try {
const { reqid } = ctx.params;
//fetch code
return {
props: {
key: reqid,
data:data
},
};
} catch (error) {
console.log(error);
}
};

React: change url without rerender; using window.history?

I have a "settings" page in my react app. The page has several tabs rendering different parts of settings.
It would be better UX if a user can share urls with other users.
What I want is (inside "settings" page):
user A clicks a tab
url changes with a #tabname appended
user A send that url to user B, and user B open that url
user B sees the same tab as user A
But with react router, the whole page re-renders if the url changed:
import { withRouter } from "react-router-dom"
const MyComp = (props) => {
...
const onTabChange = () => {
// append #tabname here
props.history.replace(...); // or `push`
...
}
...
export default withRouter(MyComp)
}
After a lot of searches, I found a solution to use window.history:
const onTabChange = () => {
window.history.pushState(null, null, "#tabname");
...
}
This does the trick, but little information and explanation, and I'd love to know the consequences of using this trick.
Is this a valid solution (for a react app)? Will this cause any problem?
(PS. I know how to parse a url)
More details:
To be more specific, there is a AuthChecker wrapper for all pages. When react router's location changes, it checks for the route's allowed auths and current user's auth.
I've tried /path/:id and everything but all change location, so auth checked and page rerendered.
And I've given up a solution in react router and just want to know: is it safe to change url with window.history in a react app using react router to manage routes?
this question is already answerd at this post.
so it says window has a property called history and there is a method on history which helps you update the history state without react-router-dom understanding it.
like this:
window.history.replaceState(null, 'New Page Title', '/new_url');

Ngrx server sided pagination with router parameters

I have a store with a simplified state tree:
{
routerReducer: {
state: {
url: '/blog'
},
queryParams: {
category: 'home'
}
params: { }
},
blog: {
posts: {
entities: { ... }
loading: false,
loaded: false,
pagination: {
sort: 'date',
filters: {
category: 'home',
tag: 'testTag'
},
page: 1
}
}
}
}
Basically, I'd like to pass down my router state into my blog state for pagination purposes, but only if the current URL belongs to that module if that makes sense? The pagination part of my blog -> posts state will be based on the URL parameters, already composed in my state. Perhaps this is not the correct method as I will no longer have a single source of truth? But I'd like to use this pagination state to essentially describe the set of entities I have in my store. That means, if I move pages or change filters, I plan on clearing all entities and refreshing with paginated content (performed server-side) from my API.
I supposed my flow will look like this:
Router navigation event e.g. /blog/2 (page 2 via queryParam)
Router action is dispatched and handled by router reducer to update
that part of my state tree
Side effect triggered on router navigation event, and if URL matches
my blog module e.g. "/blog/*" (could also contain URL parameters e.g.
?category=home) compose our local pagination state inside my blog state tree, then dispatch a loadPosts action which will be based off that piece of state
How does this flow sound? Is this the correct way of doing this?
1) It sounds feasable.
2) No. Whatever gets the job done.
What I would do
I'd create blog postPagination state where I would keep pagination data separate from entities. And a BlogPaginate action to alter it's state in reducer function.
{
{
sort: 'date',
filters: {
category: 'home',
tag: 'testTag'
}
},
page: 1
}
I'd make an effect that listens on router actions and maps the matching ones (url /blog/*) with appropriate search filters to BlogPaginate action which in turn would trigger a service call.
If you'd like to cache those entities
Making moving back to pages you've seen previously would be smoother than before. Depending on your content change rate I'd choose to either dispatch an action or just use the value in the cache if it exists.
Then I would add to postPagination state:
{
pageContents: {
// map of page to entity ids
1: [1,8,222]
}
{
sort: 'date',
filters: {
category: 'home',
tag: 'testTag'
}
},
currentPage: 1,
totalPages: 10
}
When pagination filters / sort changes in BlogPaginate reducer I would clear pageContents.
When pagination response's totalPages changes in BlogPaginateSuccess reducer I would clear other pageContents pages.
In BlogPaginateSuccess reducer I'd add/update new entities in blog posts and map their id's in as pageContents. Remember reducers can react to what ever action.
I would also create a selector that maps postPagination.currentPage, postPagination.pageContents and post.entities into an array of blog post entities.

Angular 4 - update route without appending another outlet's route to URL

I have a situation in Angular 4.0.3 where I have two <router-outlet>'s on a page.
<router-outlet></router-outlet>
<router-outlet name="nav"></router-outlet>
The first outlet will accept routes for content, and the second will accept routes for navigation. I achieve the navigation using this;
router.navigate(['', {outlets: { nav: [route] } }],{skipLocationChange: true });
This changes the outlet's contents without updating the URL - since I don't want any url that look like .. (nav:user).
The problem is the remaining outlet. I do want the URL to update when those are clicked, for instance ...
.../user/profile
Functionally, I can get both outlets to have the proper content, but it keeps appending the nav outlet's route to the url, like this ...
.../user/profile(nav:user)
Is there any way I can stop it from adding the (nav:user) part?
Unless there is some trick I'm not aware of ... I don't think you can. The address bar is what maintains the route state. So without the secondary outlet information in the address bar, the router won't know how to keep the correct routed component in the secondary outlet.
You could try overriding the navigateByUrl method as shown here: http://plnkr.co/edit/78Hp5OcEzN1jj2N20XHT?p=preview
export class AppModule { constructor(router: Router) {
const navigateByUrl = router.navigateByUrl;
router.navigateByUrl = function(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}): Promise<boolean> {
return navigateByUrl.call(router, url, { ...extras, skipLocationChange: true });
} } }
You could potentially add logic here then to check which routes you need to do this on.

How to find Popup state and refresh state in React-router?

I know this question kind a stupid But I am pretty confused with this site producthunt how they are doing this.When clicking the product list popup with react router is done like this..
But When I refresh that page it render like this..How this is done using React-router
My bet would be that they use the state property when pushing a page to give an indication to the component about how to render the page. More specifically, to indicate the component where it comes from. For example:
router.push({
pathname: '/posts/origami-studio-by-facebook',
state: { fromPosts: true }
})
And then you can read the router's state in the route's component to check what page to show.
const Post = (productName) => {
if(this.context.router.location.state.fromPosts) {
return <Posts productPopup{productName} />
// open the posts page with a popup for the product
} else {
return <PostPage productName={productName} />
}
}
So when you open the page in your browser, the state.fromPosts is not set and you get redirected to the PostPage. In the end, even if the route is the same, what you end up seing is completely different.

Categories