How to detect when ReactJS has finished page manipulation? - reactjs

Our clients add our JS tag to the head of their page. Our tag needs to know when reactJS has finished before it modifies the page.
I have tried using jQuery's $(document).ready() but this fires before reactJS has finished. I can use $(window).load() but if there are a lot of images on the page, this would be too slow.
What are the options to bind to the completion of React.renderComponent?

Set off the execution of your code via the optional callback that you can pass to React.renderComponent. This callback won't execute until React.renderComponent has finished. If you don't have access to the code that is executing React.renderComponent (which I've just realized is almost definitely the case) then there is no definitive/reliable way to listen for the execution of a function unless of course that function exposes some sort of event that you can listen for, or even guarantees that "x" will be the case once it has finished. Sadly for your case, this doesn't appear to be an option with React.renderComponent.. Let me know if you have any further question.

If you don't have direct control over the React code, you could always see if you can sniff for relevant changes via DOM Mutation events.

Related

How to unmount component before redirecting to external url?

I have a Note component where a user edits a Note. Now, in my header for the app I have a button which can be clicked and you will be sent to the base product of the company - which is an external URL.
My problem is that the componentWillUnmount function (yes, this is the "old" component based API used in this particular component) does not fire and so any unsaved changes disappear.
Ideas?
I've tried adding an event listener in componentDidMount
window.addEventListener("beforeunload", this.componentWillUnmount); but my request is still getting cancelled before the redirect. I'm using apollo with graphql endpoints btw.
I don't see how rewriting to hooks can help here.
Looks like the problem is that you, actually, do not unmount component, but leave the page. React will never know about this event.
I think, you can use another approach to keep changes: send it to the backend while user filling the note. Or, maybe, easiest way is to duplicate changes in localStorage and then recover it on new load. But it feels less secure and, of course, limited by this browser/machine
Here are a few ideas you could try:
When the user clicks the button in the header, run a function/method to save the Note before redirecting.
Add an onblur listener to Note and trigger a function/method to save when Note input field loses focus
Add an onkeypress listener and save the contents of Note with every keypress (or every x seconds to batch the updates instead).

Using #testing-library/React when is really needed to use the function `act`?

I've written some test that trigger some controlled input and need to wait for a state change.
In this case I supposed to wait for that state change and I tried to use the act function to react to that state change but it looks like the same with or without the act function.
When is act really needed?
act() docs:
When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. react-dom/test-utils provides a helper called act() that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions
Don't worry, you will know when to use it. You will get a "not wrapped in act(...)" warning like this when you test your component
This is a good post explain when should you need to use it. use cases for manually calling act(...)

React & React-Router & ReactCSSTransitionGroup

I'm creating a simple app with three states and using React's router with ReactCSSTransitiouGroup. Default behavior of ReactCSSTransitionGroup is simple:
After the click to Link append/prepend new child
New child gets "app-enter" and "app-enter-active" classes
Old child gets "app-leave" and "app-leave-active" classes
After timeout remove the old child
What I'm trying to do is to change this behavior so it can behave like that:
After the click to Link stay in the same state. Just add to the old child classes "app-leave" and "app-leave-active" classes.
After the leave timeout remove the old child and append new child with "app-enter" and "app-enter-active" classes.
After the enter timeout remove it's classes
Is there some easy way how to get this? Thanks!
One simple solution would be to not use a traditional link. If you add a custom event listener you can just start a timeout with startTimeout(namedFunctionToSetLocation, 200ms). I strongly recommend being frugal and using flags to control the state complexity, which will otherwise try and eat you alive.
In more detail:
When someone triggers your event listener, firstly set some state which will add your classes "app-leave" and "app-leave-active". You can do this in a separate function but make sure to bind the function to your component's this so it can access this.state, or pass the state in when rendering.
In that function, you also want to start a timeout, so you can do the next you do of changes after a delay. It's worth generating an ID at this point, or setting a flag, so you can check after the delay that nothing else has begun in that time (if you use one ID variable for all transitions, and just update every time a new one begins, you should have a rock solid check whether, after an async delay, you still care about continuing).
When the timeout is triggered, and you've checked your flag, you can manually trigger your router, or set a new location, however you like.
I've found it useful to use a simple bespoke approach when ReactTransitionGroup isn't a perfect fit. The transition group has nuanced behaviours with ReactRouter v4, and it's completely unnecessary if all you need is a delay or simple class change on click.
Finally, you can also use the normal ReactRouter and ReactTransitionGroup components inside of conditional rendering blocks (like those I just described)- don't pass off that technique, it's as React-ee as it gets.

A way to check if html changed in ReactJS

I have a JS code which should do some things (animations etc.) BEFORE ReactJS possibly (or not) will update HTML element. I'm getting the whole template for this HTML element (i.e. part of the page, in particular a widget) for this purpose.
For example, I have a DIV with some content, which may change in time or not. Then I get a new version (i.e. as HTML template) of that DIV through AJAX call, and I want ReactJS first to compare the actual (or virtual) current DOM with the one just retrieved new HTML template for the same DIV in a string as got from AJAX call on success. Only then - when these two are different - it makes sense to do animations first, and only then update the actual DOM in the browser by React JS.
How to do that? Is there a method in React JS that allows me to get e.g. true/false when comparing virtual DOM with its new version as a HTML template got through AJAX (since it does internally this thing anyway - i.e. comparing current and updated DOM in its algorithm)?
EDIT: Hmm after initial thought that ReactJS is way much better than other JS Frameworks in my case (i.e. server functionality is already developed), I found multiple features not flexible enough; further more, I found ReactJS is not smart enough to figure out that only one element at the top of the list is added (ReactJS replaces the whole DOM template for the list, even with keys set for each element!), which suggests it's still not that mature as one could expect.
Besides, all Lifecycle methods with ***Component***Update are not called; only ***Component***Unmount are being called in the case of mentioned list. I can do it in a simpler way by myself, however Relay / Flux + ReactJS architecture is still nice, and I think I'll just abandon Facebook's implementation, and replace it with my own solution, inspired by Relay/Flux+ReactJS.
You might want to look at the following life cycle methods:
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
From the react docs:
componentWillUpdate
Invoked immediately before rendering when new props or state are being received. This method is not called for the initial render.
Use this as an opportunity to perform preparation before an update occurs.
componentDidUpdate
Invoked immediately after the component's updates are flushed to the DOM. This method is not called for the initial render.
Use this as an opportunity to operate on the DOM when the component has been updated.

Passing Data to Directives Asynchronously

I have a handful of directives on a page that all share the same data. I have a heavy API call that needs to be made somewhat frequently to update these directives. Each directive contains the data in three states:
A display state showing the results and,
A loading state indicating that the call to the API is being made
An error/empty state
How the state is shown is directive specific and is not always a matter of updating some css or a variable. Sometimes it requires the calling of a function.
Trying to do this it seems I would have to listen for my trigger with a watch, then broadcast that I'm 'in loading' to all my directives. Then broadcast that the resource was loaded to resolve the loading state if it succeeded, else broadcast that there'd been an error. That's a lot of different broadcasts and 'on's in all my directives. Is there a more efficient way invoking direct methods on child directives?

Resources