I am trying to implement conditional rendering for our navbar's items depending on what page we're on (i.e. If we are on the chatrooms page, or "/rooms", then we don't want the "Chatrooms" nav item to render in the navbar). What I attempted to do was convert the Navbar into a class component, create a state for the currentPage and set it to window.location.pathname, and then created methods for setting the state and what nav items to render depending on the state, but it always requires me to reload the page when going from one page to another for the conditional logic to fully take effect. Is there a better way of achieving this functionality?
You could use react-router load content without refreshing the page. It's really simple to learn and use and you could probably get it up and running within an hour. You can Add Route components for the main content of the page.
When you route to a different page you could also call a setState function and change the currentPage, which in turn changes the navbar elements.
Related
In my React app, I have tabs at the top of the app, a sidebar for navigation and a section to the right of the sidebar, and below the tabs that show content. When the user clicks on a tab, the sidebar loads its navigation data from the backend. Then after loading it, by default it selects the first item in the sidebar and loads the content details. The content details are made up of different components and several backend calls may need to be made.
What I would like to do is display a progress bar just above the tabs which is shown the moment the user clicks on the tab. The progress bar is only dismissed after the entire content for both the sidebar and content details has been loaded. The sidebar and content details do not update or are even shown until they have completely retrieved all their data from the backend and done any other initialization.
Determining exactly when all the content has been loaded is tricky as each component in the sidebar and content details are responsible for retrieving data from the backend. The only solution I could think of is for each component to implement a publisher/subscriber mechanism. Each parent component notifies each child component that it needs to load its data. When the child component receives this notification and has retrieved its data from the backend and finished any other initialization, it then notifies the parent that it has completed. Only when the top-level component gets all notifications from all its direct children, does it then dismiss the progress bar and cause the content to be displayed.
Another possible approach is to have only the first child component retrieve all the data from the backend on behalf of all the descendent components and cache it in the local repository. This would eliminate the need for descendent components from having to call the backend and could quickly just retrieve the data from the local repository. But there is still the issue of initializing each nested component. If I show the entire content while it is still in the initialization phase, the user would notice this. Still, I suspect React renders most stuff so fast that users will probably not notice it.
I'm not sure if this is the approach I should be taking or if there is something more inherent in React that handles this.
A similar website where you can see this is at Google's:
https://fuchsia.dev
although this site probably has much fewer backend calls than the one I am working on. But in general, this is close to what I am looking to achieve.
Your solution with the subscriber pattern will work fine, but if you want something less complex, there are two common approaches:
If you are using redux, every child component dispatches that it is loading data right now with their unique id. When it finishes (or component is unmounted), it dispatches an action to remove the loading information. Parent component just checks redux store, if there is anything loading.
The second approach without redux is to pass a callback to the child components from the parent through props. This callback expects two parameters: unique id and bool value representing if the child components starts/finishes loading. When the child component starts loading, it calls the callback from the parent with a unique id and value true. When the child component finishes loading, it calls the callback again with the same unique id and value false. Parent component set to its state which child components are loading and renders the loading accordingly.
I noticed that when you use useState in a hook and then use setState to change the value that is being cached, the hook will be called again and re-render the component. While this may be desired most of the time, I have one case where I don't want to re-render when the state changes. This case is when you have a navigation menu (tabs) at the top of the page and when you click on a tab, it shows content in a pane beneath it. I really only want to hide the content for the tab that is currently shown and then display the content for the tab that is selected. When content is hidden, this is essentially setting the css "display" style to "none". This is desirable to preserve the state of the content's pane and also avoid effects like retrieving data.
I can think of one solution to handle this but it does require splitting the components into isolated modules. I am curious though whether there is a way to change state but without having the side effect of a component being re-rendered.
My page is composed of hierarchy of classes and many reusable components. Multiple instances of a button component can exist anywhere in the page and on click they fire actions that populate different types of data in a common sidebar list component.
The requirement is to highlight the button that was last clicked to load the data in that sidebar list. Of course, it also means to remove highlighting from the previous button. Since these button can exist in different components, I cannot manage state in one parent component.
I am not able to find a solution in pure React. I don't want to use jQuery rather just stick to React. Note I do use Redux in the app though and would be fine with leveraging Redux state if required.
You should most definitely use Redux. You'll need to create a variable in Redux that gets updated whenever an action takes place that would require you to highlight the button on the page. Then use conditional styling for the button based on that variable.
I'm trying to create single page application and one use case is i have details page which can be triggered from multiple parent pages, more like acting as modal box but without any absolute property. I was checking how to show/hide based on the state change from parent.
This is what i have done till now
http://plnkr.co/edit/t34ES8lUihcypetHF0rp?p=preview
If you take a look when clicking View Home from home DOM is not removed while navigating to next state .
But if you are in About Page and click View About, DOM is getting removed.
How can we show/hide ui-view. if we are navigating to different state with same url ?
The same url
url: '^/details/:id',
for both the states is the issue.
Try having a wrapper state say "details" and then in that state's controller you may redirect based on some parameter that tells wrapper state which state to go to.
I am trying to change the route of my url to open a map overlay. The problem is when I switch states, the page template underneath switches as well. I don't want this to happen.
I am using $statechange to detect the map route and executing an event.preventDefault(); which should stop the route template from changing. But in my case, the map url gets put in the address bar and then quickly gets removed.
Any ideas?
It seems counterintuitive to override the state change. Why don't you create the overlay as a child state and just navigate to it normally.
I managed to solve the issue by using the $state.go and declaring options 'notify' to false.. This stops the $stateroute changes to fire.