Disclaimer: I know this answer has already been asked, but in my case I need a solution for a specific case that is not really covered by other questions/answers.
In my react-native application, I do a lot of network requests that may take a long time to complete. Each request is handled in two main ways:
The request completed successfully. The global redux/flux state is updated and therefore the nested components are updated as well.
The request throws an error. A network error, a server error, a 400 error, whatever. In this case a message must be displayed to the user, in the form of a message that appears on the screen or as an alert.
My problem is that when a component is unmounted, the fetch callbacks are processed anyway when the request completes. In the first case, this is not a problem: the store is updated successfully and everyone is happy.
In the second case though, it is a problem because:
The alert would be displayed in a different screen, which is not correct and led to problems with the Modal component which I use to present error alerts.
The appearance/disappearance of the error message is controlled by the component LOCAL state, which can not be updated on an unmounted component and therefore throws an error.
What are my possibile solutions here? The most trivial one would be to use in each component a _isMounted property and in each fetch error handler, don't do anything if _isMounted == false. However, this approach is verbose and an antipattern.
Do I have any other option?
If you are using react-navigation I believe you could deduct the state in actions and not call the alert.
My suggestion is that you pass the navigation prop to action method and deduct the navigation state there and call the alert as you require.
Related
I am new to react native and I am having a warning that I just don't know how to get rid of it, is it ok if I just hide it as long as it does not become an error to crush my app?
The warning I receive:
Warning: Cannot update during an existing state transition (such as
within render or another component's constructor). Render methods
should be a pure function of props and state; constructor side-effects
are an anti-pattern, but can be moved to componentWillMount.
I tried to manage to not happen this warning but if I register a user and than go back to signupscreen and if I try to register another one the warning comes up.
It's best to resolve that warning, you need to look where your updates to the state are happening.
If you do updates to the state or props inside of your render function you are creating infinite render loops.
To help with this problem I need to have your code from render() function. You can Upload it here. Then I can review your code. It will help to solve this problem.
I am learning the Angular 5+ and recently comes to the subject/subscription part, I see many tutorial would like to use the subscription in the certain way:
Declare the subscription in component
Subscribe it in ngOnInit via a service's subject or ngrx/store
Unsubscribe it in ngOnDestroy
However, I am not sure if we have to subscribe/unsubscribe every subscription in the component in ngOnInit and ngOnDestroy. For example, if my subscription will get updated through a button click event, which plan should I subscribe it in my component?
Only ngOnInit
Only button click event
Both ngOnInit and button click event
Why would we always subscribe a subscription in ngOnInit? The ngOnInit would be like a Page_Load in page life cycle, so it would only be called once at the very first time, if so whenever the subscription gets updated, will the ngOnInit be fired over and over again? If so, will my component be loaded over and over again which would cause a performance issue if in large application?
You usually put Observables to subscribe to inside a Service and make them available via getters and setters.
When subscribing to an Observable it behaves in a certain way like an EventListener. Whenever the object inside the Observable gets changed, an Event gets fired and your code inside the subscription gets executed. Additionally, you get provided the updated object.
Even if you init the subscription inside ngOnInit this won't cause your entire Component to reload when an update arrives. Only those parts that get updated by your code inside the subscription.
You don‘t have to put a subscription inside ngOnInit(). It depends on what you want to achieve in the component. But most of the time you want to load and display data directly when you access the component and update the UI when this data changes. That's why it is good practice to put the subscription in ngOnInit().
When I provide loadOptions to an Async control it loads options on mount.
If I pass autoload={false} then it doesn't load options neither on mount nor on open. But it loads options on the first close (or type, or blur).
If I pass onCloseResetsInput={false} then it doesn't load options until I type something. (showing "Type to search" in the menu)
Async provides onOpen handler, but I didn't find the way to use it in this situation. (and react-select#2.0.0-alpha.2 doesn't have it)
So the user needs to type a character, then delete it, to see the full list of options.
How can this be avoided?
Example sandbox: https://codesandbox.io/s/mjkmowr91j
Solution demo: https://codesandbox.io/s/o51yw14l59
I used the Async options loaded externally section from the react-select repo.
We start by loading the options on the Select's onFocus and also set the state to isLoading: true. When we receive the options we save them in the state and render them in the options.
I also keep track of optionsLoaded so that only on the first focus do we trigger the call to get options.
In our use case, we have several of these select inputs on a single page, all async, so the requests to the server will pile up, and are completely unnecessary in a lot of cases (users won't even bother clicking).
I found a workaround for this issue that'll work for my use case on 2.0.0-beta.6:
Include defaultOptions
Add 2 members to your class that will store the resolve/reject methods for the promise.
In your loadOptions function, check if the input is '', if so, create a new promise, and store the values of resolve/reject within your class members, and return that promise. Otherwise, just return the promise normally to get your results.
Add an onFocus handler, and within it call the function to get your results, but also add .then and .catch callbacks passing the resolve and reject functions you stored previously.
Essentially, this makes react-select think you're working on getting the results with a long-running promise, but you don't actually even try to load the values until the field is selected.
I'm not 100% positive there aren't any negative side effects as I just wrote this, but it seems like a good place to start.
Hope this helps someone. I may submit a feature request for this.
In order to load options when user focus first time, set defaultOptions={true}
Thanks, Alexei Darmin for the solution, I was struggling with this... while testing it I converted the solution to a react functional component and added real API fetching.
Here is a working demo, I hope it helps someone
Is there any way I can ask the VueJS to wait for a while before handling the DOM bugs?
I have for example a select that receives av-model coming from the API, but as VueJS loads the DOM first before the http call, it already accusesselect error
type check failed for prop "options". Expected Array, got Undefined.
This error is right because it draws the DOM with nothing in the select, but then it fills in with my call to API. Is there any way I can ask VueJS to wait a little bit for me to bring the API data and then it checks DOM?
Thank you!!
Note: I know that initializing the parameter with empty array works, but wanted another way without being manual
The situation. I have an a custom alert component in a shared components file. I have my different screens in their respective files, and they all import the custom alert. On navigation away from one screen to another, and then I navigate back via reactnavigation's back arrow, the alert is not remounted, and so its invocation throws an error. How should I take care of this?
I figured out a hack; so long it works for now and maintains the development momentum. So, prior to any function call that will eventually invoke the custom imported alert, I call setState, and update a dummy value, e.g. this.setState({sth:'sth'}). This seems to in turn, reload the component's relation to its imported stuff, and just like that the error is no more.