I need to reset a child component from parent. I know the best way is to send a props. So I send reset = true as properties. But looks like I need to have a callback function to parent from the child to change that properties to false after reset is done, so if it happens again, the rest works.
I do not want to use refs as it is not the best method, but I do not want to have callbacks too.
What other suggestion you would have?
Related
I'm using a React component library and populating a modal (Parent) with a complex stateful component (Child). This generic modal also has a footer with a save button. The user interacts with the contents of the modal (Child) and when they are ready, they click the modal. This saves to the server, the current state of the internal component.
I'm trying to understand the best way to accomplish this in React. Right now, the child component is using useImperativeHandle to expose a getData() function that is used by the click listener callback in the parent modal who then calls the server. This feels wrong. What I'd like is the parent component to tell the child to save its contents when the user clicks on the modal save button. I don't think the modal should contain the save logic that contacts the server.
Please let me know what are the best practises for this case.
Thanks!
Agree, it does feel weird for the parent to request data from a child at the time of submit, so data ownership should either be in the parent or at a shared data source (initialized in the parent).
On the parent side, not sure of how many changes may get fired by the child (perhaps when the process is completed), but thinking you could have something like an onStuffChanged callback on the child that sets values in the parent to use on the submit.
On the shared data source (keeping it to React), you have a reducer or context. Context might be overkill here since it's just a parent / child relationship.
Will use reducer as an example here, but there are many other libraries that could solve this with state management. Basically you can pass the dispatch to the child and have it update the data store as needed (i.e. when it has all the data needed to submit). The parent submit button can then use the data stored there.
Basically suggesting either a child callback or shared data source / state management pattern that the parent and child have access to.
I am running some tests with react to find out a way for a parent to send an "event" to a child component. In the test application, the parent (CounterController) has a button. When the button is clicked, the parent shall send a reset "event" to the child (Counter) to reset the current count. Like below.
I am new to react, and can not find a way to dispatch/receive events or messages between components. I had a thought to mark the "reset" request as a "state" in the parent, then pass it to the child through props. Then the child clear the "reset" state, through a callback function, to avoid repeating "reset" requests. However, I got the code run into an infinite loop. Here are my codes.
The parent component - CounterController
The child component - Counter
the error logs
I do not feel that I am using react the right way, by asking the child to do something from the parent. Anyway, any idea about how to implement this app in react? How should the data flow be built correctly? Thanks!
You can move up the counter state on the parent ‘CounterController’
and then you pass the counter and setCounter as props to ‘Counter’
You don’t need ‘reset’ state
I am posting my thoughts about using react (as a beginner), and my solution to the app.
treat the react components as the "view" of the application, and maintain the data and controls in the hooks.
create a custom hook to wrap up all data and controls.
create an instance of the custom hook in the top component - display the data in HTML elements and bound controls to buttons to build the app UI
Here are my codes for this simple UI
UI
useCounter hook
counterController component
counter component
Move "count" state from child component (Counter) to parent
component (CounterController).
Pass count state as prop to child component.
Pass increment and decrement methods from parent to child component through props.
Note: Remove reset state, it's not required anymore.
Sandbox link : https://codesandbox.io/s/infallible-platform-vo4qtv?file=/src/CountController.js
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.
I know the main concern about when to put something on the state or receive as props, but what about when I have something that is suitable for both? I have items that should be 'active' when the parent is active(props) and also have the option to toggle this attribute from a click event(state).
It sounds like what you want is something like a parentActive variable held in the state of the parent and passed as a prop to the child(ren). Then a childActive variable held in the state of the child that is toggled by your click event. Then you'd simply have some logic / a conditional within the child that determines whether it's active. For example:
// Within child component
if (this.props.parentActive || this.state.childActive) { }
In general, when you have a new value that needs logic, you store it in state, create the click handlers that you need within that component, then pass it off (and possibly its click handler) as a prop for children. In your case, you need logic for a value/active flag within the parent, and logic for a value/active flag in the child.. so it sounds like you would want to set state in both of them, and pass the parent value as a prop for the child.
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.