Let's say we want to create a new Task. We have 2 categories of information we want to collect from the user for creating a new Task: general params, action params.
To make it easily separated we are separating between them with tabs. so each gets its own react component, both stored in different react-tabs tabs.
In the parent component I have a save button and I want that at any given time, the user could click it to send the entire state from both the tabs' state to the server.
While I could forward event handlers from the parent to the children (as suggested by other questions on this topic)... doing it for each of the 20 controls (dropdowns, textfields, date time pickers) in each of them requires a lot of boilerplate code and seems unreasonable.
I'm looking for a best practice for this situation. Thanks!
Related
If there is no mistake:
React-Router's <Link/> component can carry over data (state) when the user doesn't leave the current tab or you force the user to open new tab on left click using target="_blank". Otherwise the state you send with it is lost because we'll have a new empty history stack.
localStorage can be used to share state between tabs but it's problematic in scenarios where i just want to store the data for only the regarding tab user is expected to navigate.
e.g. I want to set a state using the state/data I've stored for that specific tab and doesn't want to store it anymore/ forget about it. In this case, synchronization problems may occur when the user actually creates multiple tabs using the same <Link/> component but doesn't navigate to all of them. How?
Say, I've removed the state item from the storage when the component is unmounted in one of the tabs user is already navigated and, later on the user is navigated to another tab expecting the item in the storage to set the state. (The component in this tab will try to set state with non-existent data / will crash.)
I could hold the state till the window's onunload event is fired at best, but the problem still exists because localStorage is shared across all of the tabs and removing an item affects all the tabs like i've mentioned. ~ I have to remove the items somehow, can't rely on storage of 2MB to 10MB forever. I tried to find other solutions like clearing it once in a while on user logout/login but that would force the user to take those actions again, once in a while.
So I want to be able to store selected the state/data on sessionStorage of the newly instantiated tab and it gets cleared for me when that tab is closed and I don't have to deal with the regarding problems.
The problem could be defined with simpler words as:
I want to send a piece of data from one tab to another with empty history stack in the scope of only that tab.
Because I don't need it anywhere else.
I can do things like setState using that data, remove that data etc. and the other tabs launched in need of that data don't get affected.
I've searched through the other questions but there are not detailed answers covering this scenario or I couldn't come across with a best practice for this kind of stuff using ReactJS. Sorry If this is a duplicate.
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.
What is the best practice to implement a multi step form?
I know that there are several different practices, but which one is the best/most performant ?
Redux/Global state management: Easiest but bad for performance, because it will check every connected component on every key hit.
Raised State: Have a parent component keeping all state, but this couples the components too close together and makes the parent component too complex
Render props: The child components render the next button of the form as a render prop and push their data to the parent on next click => this makes the parent complex as well and it may be difficult to pass the data to the parent.
What are your thoughts? Thanks in advance!!
I would go for the second option, because it keeps the children simple and dumb (MVC).
The parent component keeps track of all data and which form is currently displayed, which keeps all logic within one component (which makes it easy to update).
Performance won't be a problem, because it only displays one form anyway, so the performance is the same as if using a single form.
I have an event component and a container class that lists the events. I am struggling with deciding between these two options
Have the container class get the list of event_id, pass the event_id to each event component, and have each event component fetch its own data.
Have the container class get the list of events objects, and pass the event object in as a prop to the event component.
The user can edit events, so the event components needs to be able to handle updates.
With option 1, I will only need to make one fetch to the rest api, but then the container class has to manage the state of each event in case of edits.
With option 2, I will have to make a fetch request for each event, but then each event object can manage its own state.
Which option (or any suggested 3rd options) should I implement?
I'm with the first choice ...
It's better always to reduce your requests.
And in react it's better to make your design such as .. less containers .. more components
I mean that if you can manage all your components in one container this would be a better solution
Another Case .. Maybe you'd have to transfer state or to make interactive between event components .. this would be much harder if you make every component fetch data by itself
So I'm with the first choose
Update:
Will it be displayed with the same event handler ? If yes .. than the other choice will be better
what I mean that: some time you have component with event handler .. but this event will be handled differently in each parent component(like when you have custom button components with some styles .. but one-click event will be handled differently depending on parent component) .. so the first choice will be better
but if it's handling same event in the same way each time then the second choice will be better
Both the approaches are correct, and nothing wrong to go over another.
It all depends on how your UI wants to show these events. If data from multiple components (event component and a container class in this case) needs to be in sync, then move state data to closest parent component of the components that need it and handle updates through callback functions. If not, move individual event operation in child(event component in this case) component
I have trouble coming up or finding the boundaries of the so called "UI State".
Imagine the example of an issue tracker:
We have a list of "issue cards", which each contain:
A simple icon that represents the progress (i.e. open, closed)
The description text of the issue (a simple <p/> element)
A single Action button that changes d =epending on the state of the issue: "Assign to myself" or "Mark as done".
A button that opens a context menu (AKA right-click menu). This menu has a list of a variety of action buttons. Depending on the
state, some actions are greyed out and can not be clicked / or are
just not shown. Like "Close Case", if the case is already closed.
If you could categorize each of these items into UI-State vs. Application State, it would help me understand the boundaries.
More practically: How would you divide this little example application into containers and presentational components?
My interpretation: 1. and 2. are just presentational, 3. and 4. are stateful. Is this right? How would I structure this as containers and components?
Thank you very much!
All of listed examples are examples of application state, where UI is determined by persistent data that is received from the backend.
UI state usually refers to UI component local state that is determined by user actions, e.g. window position, active tab, unsubmitted form values, etc. Depending on the case, UI state may be lifted up and stored somewhere (persistent storage or URL) or be discarded.
if I want to implement this project I would act like this :
a component for managing all children components
a store to managing model, data and fields
a component for displaying icon and description text and button
a component for context menu
please consider that if you are using MVVM pattern, be sure that all responsibilities of actions are done by store and for changing some properties use observable fields
and if not use state in manager component and pass via proprs in children.