throw error after everything is rendered in react - reactjs

I am trying to create a react HOC that would render its children, and then after all the children had finished updating BUT BEFORE THE DOM is updated, would decide to raise (or not raise) an error, depending on some flags the children would update.
<Try alternative=... >
... do some stuff // if anybody in here sets a flag we will
// render alternative instead
</Try>
Why? It would be useful to allow all the children of Try to complete rendering and then if any were waiting on some async callbacks, to render the alternative. Kind of like an error boundary but it would all the enclosed children to re-rerender first.
Having the first child that hits the condition raise an error doesn't work, since it doesn't allow the rest of the children to finish.
Using an componentDidUpdate handler in Try won't work either, since it won't run unless Try actually changed (I think).
I am hoping somebody will know of a secret, or expermental trick that might work.
Thanks

I think you are over-complicating things. Why not take a simple approach that achieves the same goal?
Your callbacks will set some sort of state. So that means, if the state has not been set, the callback has not been run.
In your child components you can check to see in the state has been set. If the state has not been set; then, display your "Please Wait" message.
The "Please Wait" message can be extracted into its own component and be used throughout the entire website. By extracting the code for the "please wait" cover, all components can then use it instead of implementing their own version of the "please wait" cover.
I think this is a lot more simply and effective then what you are suggesting.
EDIT:
Regarding the flickering mentioned in comments. That shouldn't happen. Where I was trying to go is have a "Cover" component for the "Please Wait".
The child component would check it's state to see if it is ready to display it's main content. If not, the child component would use the Cover component.
In otherwords:
Child Component is constructed
Child Component's State is not ready. Child uses Cover component
Child Component's State changes (due to async callback)
Child Component Starts Re-Render Process
Child Component's State is ready to render main content
Child Component renders its own content
This is fundamentally different from what your comment had said. The parent would not render the Cover. The child would use the Cover component when it is not ready to render its own content.

Related

Ensuring Child Component Reloads When Parent Component Changes

I am working on creating an updated implementation of an existing react native app and am running into a situation where a child component doesn't re-load when the parent component changes.
My situation is this: I have a parent component for a particular record. Connected to this is a VisitTimer child component that keeps track of duration for a that record's session. What I'm noticing is that, when I load a record into the parent component for the first time, the child component <VisitTimer> does fire with componentDidMount(). However, if exit that screen, and load a DIFFERENT record, then the child <VisitTimer> component does not mount - i.e. componentDidMount in the VisitTimer child component does not fire.
What is the likely issue here? And how can I ensure that a child component always re-mounts when the parent component changes?
Here is the child component within the parent:
<VisitTimer
started={this.props?.session?.dates?.started?.value}
stopped={this.props?.session?.dates?.completed?.value}
durationOverride={this.props?.session?.duration?.total?.value}
maxDuration={maxVisitTime(this.props?.session?.type?.value)}
visit={this.props?.session}
ref={(ref) => (this.visitTimer = ref)}
stopTimeOffset={this.props.visit?.duration?.stopOffset?.value}
editable={statusCodeToEditableLevel(this.props.session?.status?.value) === 2}
onChange={this.onSessionTimerChange}
/>
See my comments but a way to force this to be recreated is to give it a unique key based on the record. In react, key is special, and if it changes the whole component will remount. You could set the key to a unique id from the record:
<VisitTimer
key={this.props?.session?.guid}
started={this.props?.session?.dates?.started?.value}
stopped={this.props?.session?.dates?.completed?.value}
durationOverride={this.props?.session?.duration?.total?.value}
maxDuration={maxVisitTime(this.props?.session?.type?.value)}
visit={this.props?.session}
ref={(ref) => (this.visitTimer = ref)}
stopTimeOffset={this.props.visit?.duration?.stopOffset?.value}
editable={statusCodeToEditableLevel(this.props.session?.status?.value) === 2}
onChange={this.onSessionTimerChange}
/>
I made an assumption the unique id is on session.guid.
By the way, this is generally a good idea over implementing componentDidUpdate in your situation. People often go that route and spend loads of time implementing reset behavior to set the state back to its original values, which is a source of bugs. Changing key guarantees you have a fresh start. The only time you shouldn't do this to achieve a "reset" on a component is if remounting it and its children are expensive.
Using a key will force a re-render but that's not the primary purpose of key. React docs do talk about using the key like this but those are for specific use cases. In this case I would encourage to ask ourselves:
Do we really need to re-mount the child component or do we just want it to re-render
Regardless of the answer to the above question. Why do we need the child component to re-render. Is it because it needs to show an updated data?
If yes, then the child component should receive a prop from the parent or something from a global state which changes (in your case probably the record itself). That kind of prop change/state change will automatically trigger a re-render
I hope this is helpful but the community can be even more helpful if you can share more details of your problem like - What does the parent component do, what does the child render, why do we want the child to re-render, etc

How to pass data from grandchild to parent component in React?

I have a form (Parent) which contains an input field (Child), which gets its value from a reference table (Grand-grand-child) that is displayed as a modal (Grand-child) which opens up by clicking a button attached to the input field. This is a nested structure that roughly looks like this:
I need to set the value of the input field by selecting a row in the reference table and confirming my choice with a button "SET VALUE", which means I need to pass data three levels up from Grand-grand-child to Parent through Grand-child and Child.
My state is kept in the Parent component. Is there a simple way of achieving that without using external libraries? Please offer a solution using Hooks as all of my components are functional components.
Here is the code: https://codesandbox.io/s/festive-fast-jckfl
See CreateRate component where:
CreateRate.jsx is the Parent
InputField.jsx is the Child
DataFetchModal.jsx is the Grand-child
Airports.jsx is the Grand-grand-child
Pass a change handler function from parent (where state lives) down to the grand child. The grand child should call this change handler when clicking the Set Value button.
If this is too much prop drilling
look into component composition first
if that doesn’t work out, look into context api
Update:
You mentioned your problem was trying to access the state inside Grand-grand-child from your Grand-child. In this case you can lift the state up (to Grand-child). This means lifting 'airports' up to DataFetchModal. Here is more info on lifting state.
https://reactjs.org/docs/lifting-state-up.html#lifting-state-up
Also, it appears you are running into these problems because your code is very nested and not very composable. I would suggest looking into how you could better break up your components. One way to accomplish this is using compound components.
https://kentcdodds.com/blog/compound-components-with-react-hooks
Determining how to break this up better would take some time. However, just looking at this briefly. You may be able to move your DataFetchModal to your parent. Pass a callback to the InputField to fire it off and send the identifying parameters (what input called it). Then, from the parent, compose in whatever modal body using composition. It appears you have a lookup object (objType) inside DataFetchModal. Maybe this could go away by using composition (not sure, and probably separate topic).
Update 2:
I pulled down your code sandbox and made a few changes that may help access parent level state. I moved the modal into the parent. Check it out.
https://github.com/nathanielhall/Test

Trigger a function in a child component

There is some related threads, and a lot of opinions on this subject so I will try to summarize my findings. Notice I am a beginner so this is my best bet, and the data I gathered from related posts and this.
In general most people agree that if the parent call's a child it is bad practice. In the related post for this article there is an accepted answer, where the person answers that it is a bad practice but possible. #mat sz answer directed me on the right path. I have updated my sample for others to see. I pass a parameter to my child component. In the child component I add a listener for changes on that parameter:
useEffect(() => {
if (props.toggleClose != null) {
setToggleJobTable(false);
}
}, [props.toggleClose]);
I just toggle that parameter between true/false in my parent. Not beautiful but my best bet on how to do this in react.
Original question
I found a lot of samples in here on how to pass variables to child components, how to raise events from child components to parent components, and even how to pass a function to a child component from parent component. But what about last scenario. How to call a function in a child component from the parent. In this sample I would like to trigger the closeAll function in the child component from the parent:
https://codesandbox.io/s/toggle-all-qxkgy?fontsize=14&hidenavigation=1&theme=dark
I still dont have an answer on this, but a lot of good input in the posts. For me it sounds like the right approach here would be parsing a parameter to the child as parameter. My question is then, if I pass a parameter to the child component. How do I toogle when the parent changes that value, then my closeAll function in the child is called?
It is also stated that it could be wrong design. If you look on my very simple sample how should it else be designed? All input are welcome. I have very little experience with REACT so I am trying to understand how an experienced REACT developer would solve this simple task/sample.
It's not possible, parent components are not able to access the functions inside of child components.
You could use something like Redux or MobX to create a global state and then rely on global state for that, or you, ideally, should restructure your code in a way that does not require this, for example if your function (the one that has to be called inside of parent) changes state of a child component - move that state to the parent component, and then provide that state via props to the child component (along with a setter function, if required).

React callback to scroll after all children are rendered

I need to execute a piece of code after all grandchildren of a Component are rendered to scroll to one of the grandchildren. The structure looks like this:
`<GrandParent>
<IntermediateParent>
<IntermediateParent2>
<GrandChild/>
<GrandChild/>
<GrandChild/>
<GrandChild/>
</IntermediateParent2>
</IntermediateParent>
</GrandParent>`
The render method of GrandParent looks like this:
render() {
if (!this.props.listOfGrandchildren) { // still loading data from server
return <div>LOADING...</div>
}
return <IntermediateParent grandchildren={this.props.listOfGrandchildren} />
}
It is clear that using ComponentDidMount will clearly not work because of the children being mounted at a later time, after the data is loaded from the server. In this case, CDM of GrandParent would be triggered before CDM of any GrandChild
I could pass down a method from top to each GrandChild that would be called at CDM. On GrandParent I would wait for all GrandChild to call that method by using a counter and once the counter would be equal to the number of grandchildren I could call my piece of code that would scroll to the wanted grandchild, but this feels like a lot of hassle.
I want to load the GrandParent before the data comes down from the server, to render a placeholder/loading element.
I am looking for a more elegant method to solve this.
UPDATE:
Is componentDidMount of parent called after all componentDidMount of children?
I know why my GrandChildren's CDM is triggered after CDM of GrandParent just looking to have a different behaviour
In the end the most neat solution was the following:
I set up ComponentDidMount on IntermediateParent (works with IntermediateParent2 as well) which calls an action creator that sets a flag loadedX = true.
Then, in GrandParent's ComponentWillReceiveProps wait for the loadedX prop to become true. When this happens, manually call the desired 'callback' function. I inject the loadedX prop to GrandParent using connect.
Hope this also helps someone else. If you need more details ask in comments. I can also come up with some code for a more real world example.
We know that the children will render() when the parent render()s. This means we need to hook onto a parent render() and see if the children exist yet. We don't want to hook onto a child render() because that will run too many times and is kind of out of the scope of the child.
Looking at the React Component Lifecycle, we see that there are two ways to hook on after a parent render(), componentDidMount() and componentDidUpdate(). We know that we can't use componentDidMount() because the parent mounts before the children. However, we can use componentDidUpdate(). In your componentDidUpdate(), you can use refs, document.querySelector(), document.getElementById(), etc. to get a reference to the child. Once you are able to get the child reference, set a boolean flag so you only run the callback inside componentDidUpdate() once.
I feel like this is a cleaner solution. I think the accepted answer is kind of roundabout. You modify the IntermediateParent with ComponentDidMount(), actions using a dispatched redux action or a callback function in parent, and then the componentWillReceiveProps(). The componentWillReceiveProps() will also require a boolean flag like my solution.
Actually, maybe it isn't out of the scope of the child. Another solution is for the parent to pass a callback down to the child to call during the child's componentDidMount(). This callback will be called each time a child mounts, but you can keep a boolean flag in the parent so that the code only runs once.

How do I get the owner or parent of a react component

Is there any way for a react child component to find out its parent without explicitly adding a ref on the parent, that is passed to the child?
Perhaps some undocumented property ?
There is actually a _owner property, but it's intended to be private, so it is not guaranteed that it will remain accessible in future react releases.
componentDidMount() {
console.log(this._owner.props); // Logs parent props-object.
}
However, as this will probably stop working one day and I want my conscience to be clean, it forces me to suggest that you pass a callback or refactor how the data flows in your application.

Resources