Managing a large state tree in React - javascript

I have some data in the rough form of:
Parent->child->grandchild->great grandchild
I have created a component for each level in the tree, with the top component storing the whole tree as state, and passing branches down via props etc to its children.
As the top component manages the state, it is responsible for CRUDing any of the children. If I simply want to add a new great-grandchild, I will have to replace the entire state tree on the parent component. Is this a vastly inefficient approach, or will React work out which components to re-render? Is there a better or more idiomatic way of achieving what I need?

For this React supports "keyed children". This basically means adding a key={someUniqueId} attribute to all your child components.
"When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused)."
To answer your question
Is this a vastly inefficient approach?
Yes, if you do not use keyed children for every small change in one of the leafs the whole tree will be rebuild from the root up.

Related

React - How to get child component's position in ancestor component

I need to get a child component position in a tree in my React app to make a 'tour/guide' for my application. if it was vanilla js, I was able to easily get the target node using document.querySelector() but since in react we have to use refs to get access to the element, and it's not a good way to use refForward in many child components to approach the target one from the grand parent component, what is the best solution to get properties of a child component in a tree?
I think one possible solution is saving target elements' position in a global state manager like context or redux, but since the position is changing frequently, it would cause some critical performance issues in the app.
Thank you in advance.

Separating components in React

I have a parent component that has state and a child component that uses the youtube-react api to create a video player. The child component contains both state and methods that are used to work on the video player (e.g. event handlers).
I want to ask if should I separate out the child component by making it a stateless functional component? I can do this by placing all the methods and state of the child in the parent component and then pass all relevant methods/data down to the child via props.
My concern with separating the child component is that will make understanding how everything works confusing. Also, it will result in a huge parent component as the parent component already contains methods and state for other child components.
I think it all breaks down to personal preferences. I like to write components which are reusable and handle all the logic by themselves, so that I can use them as often as possible. This could result in some components get bigger then others.
I think a good starting point is here: https://reactjs.org/docs/thinking-in-react.html

Is it OK to put a container in a component in Redux?

I'm hacking with React/Redux and have been building lots of container and components.
However I recently encountered a design choice I made that made on of my Elements look like this:
My question is is this design OK? Basically I am struggling how to pass the Redux Actions down to the Button, since the button is a few levels deep. I could keep passing the actions down component to component from the HeaderContainer, but if the DOM got deeper it would just get worse and worse.
I feel like this design is WRONG since a presentational component is calling a container component.
Any thoughts?
You have three options:
First is to directly connect the button component to the store and let it be both container & presentational component. Simple and effective.
export default connect(mapStateToProps, mapDispatchToProps)(ButtonComponent)
See an example from the creator of Redux here (the 4th post)
Second is to create a container to wrap the button and let the button be only presentational - your current implementation. Very good layered architecture, but overengineered at this point for me.
Third is to pass the action down from the HeaderComponentContainer to the ButtonComponent.
I would go for the third one if the button is no more than 2 levels deep, since you already connected your HeaderComponentContainer and as a parent it is its responsibility to determine what functionality its children should provide (they only present, right?).
PS. You can use React's context to pass actions / properties arbitraly deep in the hierarchy without explicitely doing it for each component.

React-Redux vs ReactCSSTransitionGroup

I've encountered an issue connecting redux and ReactCssTransitionGroup. I'm wanting to transition old elements out and new ones in. The movement is fine but because redux is breaking the Parent/Child prop relationship, the old elements are being rendered with the new data before exiting.
There's a fiddle below that shows the relationship with a single child and only one level deep.
<Parent>
<Child/>
</Parent>
For this case it would be easy enough to pass the props directly, but I was hoping for a solution that would play nicer with a more complex structure:
<GreatGrandParent>
<GrandParent>
<Parent>
<Child/>
<Child/>
...
How might one prevent the children from updating when the transition is triggered?
https://jsfiddle.net/haygoodjon/wx0L0bx7/2/
^
The fiddle is updating the old time before removing it from the dom. The expected behavior can be achieved by removing the connect on Child and passing the time prop directly from App

How to preserve a component's instance while moving it to another parent component in react?

Suppose we have two sibling react components called OldContainer and NewContainer. There is a child component inside OldContainer that contains a <video> tag, and the video is currently playing.
The user can now drag the child component (with the video) and drop it in the NewContainer, and they expect the video to keep playing while it's being dragged and after being dropped.
So the video appears to stick to the mouse position, and when dragged and dropped in the new container, it animates to its new position (again, it doesn't get paused).
How would you implement this? Can we implement this in a pure way (in line with the spirit of pure functions)?
Clarification: I could have used some other element instead of a video tag for explaining this problem. A NumberEasing element would be a better example, since it would require the props and state of the component to be preserved during and after the interaction.
Update 1: Code examples obviously would be nice, but what I'm mainly looking for is just a general description of how you would approach this problem in a "functional" way. How do you keep your view code simple and easy to reason about? Who handles the drag-and-drop gesture? How do you model the data that's fed into the views?
Take a look at this library : react-reverse-portal
What is it that you want to preserve? Is it Javascript objects that the component holds as state, or is it state in the DOM (like how long a video has played, or text selection in an input box)?
If it's just Javascript objects as state, you're better of moving the source of that state to another service (something like Flux). That way, it doesn't matter if the component gets recreated because it can be recreated with the state that was there before.
EDIT
The way to keep your view code simple and easy to reason about is to not keep state inside your components. Instead, all data that the component needs should be passed into the component as props. That way, the component is "pure" in that it renders the same output given the same props. That also makes the problem of wanting to reuse a component instance a non-issue, since it doesn't matter when the same input gives the same output.
For drag and drop, I'd suggest looking at: https://github.com/gaearon/react-dnd.
How you model the data you pass to view components is up to you and the needs of your application. The components shouldn't care, they should just expect to get data passed as props, and to render them. But the popular approach to dealing with this is of course Flux, and there are many libraries that implements Flux in different ways.
SECOND EDIT
Regarding if you have a subtree with hundreds of components that you want to move: I'd still start off by making the state external (pure components), and render that tree in a new place. That means that React will probably recreate that entire subtree, which is fine. I wouldn't deviate from that path unless the performance of it turned out to be horrible (just guessing that it might be horrible isn't enough).
If the performance turned out to be horrible, I would wrap that entire subtree in a component that caches the actual DOM tree and reuses it (if it gets passed the same props). But you should only do this when absolutely needed, since it goes against what React tries to do for you.
THIRD EDIT
About gestures: I'd start out with listening to gesture events in componentDidMount, and in the event callback call setState on the component with the coordinates it should have. And then render the component in render with the coordinates given. React won't recreate the component when you call setState but it will re-render it (and diff the output). If the only thing you changed was the coordinates, it should render fast enough.
If that turns out to be too slow, like if the subtree of that component is huge and it becomes a bottleneck to recreate the subtree of vDOM, I'd reposition the DOM node directly in a RAF-loop outside of Reacts control. And I'd also put a huge comment on why that was needed, because it might seem wierd for some other developer later.
Create a new variable using const or var. Put the instance of data using rest spread operator, update the necessary data to pass and send the data to the component without mutating the state of component.
Just like:
const data = {
...this.state.child,
new_data : 'abc'
}

Categories

Resources