I have a relatively simple app with a header and a main section of content. The main section can show up to 4 different types of components, but only 1 component at a time. Each component needs to have the ability to transition (slide) from one component to the next depending on the state.
As of now my main application component holds the state as to which component should be shown. This main application component also renders all 4 of the top level components. Each of the 4 top level components hide/show themselves based upon the application state. Is this the best way of toggling the different components on and off, or should I manually mount and unmount each component? If I take the mount/unmount approach am I still able to easily transition each element?
I would have upvoted or commented on Douglas' answer but I dont have enough rep!
ReactCSSTransitionGroup will do what you want. Adopt the tutorial example to suit your purposes and dont forget to write your animation styles first (ReactCSSTransitionGroup relys on CSS animationend callback to know when the elements have left/entered the dom). It will add helper classes for you so you can create a transition effect between the (incoming and outgoing) elements.
A ReactCSSTransitionGroup will probably do what you need, at the very least you could look at the implementation to see how they do it.
Related
I created a layout component for my react app, and I wanted to dynamically update the side bar and navigation bar on route change.
I can use redux, but all of the state and methods will be available at all times, even if i don't need them.
I also looked at the new react context, but it has the same problem as redux.
With react router, it looks like i'm just mounting a new sidebar or navigation bar.
Is there a way to dynamically provide new state and methods to my layout component?
(replace the state with a different one, or multiple new once: apple --> orange)
React router looks like my best option, but I can do the same thing by just including the sidebar and navigation bar with each new route.
Dynamically adding links is not a problem, adding a button that affects the newly mounted component is the problem. The navigation bar and side bar lives in the parent component, so they need to know all of the states and methods.
Thanks,
Edit:
Example:
- Home - About - Contact
No problem, with link. I can just replace the link components with any other component with a switchComponet method.
Stop - Speed-Up - Help
These are all buttons. Now I need to add their methods and state to the Layout component. Is the app grows, more state and methods will need to be added to the top component.
I can place all of them in redux, but all the state and methods are always available. I probably have the wrong impression about redux, I'm thinking that it might take up a lot of resources, but I might be wrong.
My guess is that by "state and methods" you mean the mapStateToProps and mapDispatchToProps arguments of the react-redux connect function in your layout component.
If that's the case then you have reasons to be concerned about putting the logic of all possible content of your layout in there.
I think your problem is that you're assuming that you have to connect only the top container to redux when it's not the case.
You can connect your layout component to deal with the nav and side bar and at the same time having components nested in your layout component and connected to redux with their own store keys (part of the store state) and actions.
This way you don't need to add all store states and action needed for each layout content. Each layout content will stay close to its logic.
That's actually one of the purposes of redux.
By this I mean, when mounted, the enter animation is ran, and when removed, the leave animation is ran. I have a transition that needs to animate a number of elements within it on enter and leave, so I want to move all the code into its own component, then
<template>
<transition #enter="enter" #leave="leave">
<!-- component -->
</transition>
</template>
---
<CustomComponent :key="indentifer" :indentifer="indentifer" />
Full example of my attempt: https://codesandbox.io/s/znq6l8p94p
As far as I am aware this is only half working because of the appear, i.e. it's just mere coincidence.
I feel like the only way I can solve this is by doing all the animation and state management in one component, as in a component that knows about the old and new sentences or use a transition-group, rather than just leaving Vue to manage that for me via my use of the key attribute. Am I perhaps misunderstanding how best to do transitions in Vue, should the animation all ways reside with the parent of a component?
After writing this out it feel like what I actually want is lifecycle hooks like transition-group offers, but which call the child components methods directly.
My current understanding is that during v-on:leave the component is no longer reactive, and you should only be doing manual dom-manipulation...
Instead, my solution was to create a component that handled the adding and removing of the elements via a watch and then passed the array through to my component in props.
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.
So I have an app that has a right sidebar whose visibility is toggled via a button. In that sidebar there can be one of several things [at a time] - chat, help, search. I was looking at some plain HTML from apps which have a similar feature and noticed that they have all nodes rendered, but are just hidden via CSS.
Since I need to do the same thing, I was thinking whether this would be a good idea to do with React. But then I realized that React elements have a state which when updated calls the render method. So I can use the state to store both whether the sidebar is opened, and what is inside the sidebar.
Is that the React way of doing things? Is it better to have all nodes rendered even if they are not visible, or is it better to have the nodes rendered on request via state changes?
My feeling is that only rendering what is visible would be the more standard React way, but in this case, this is mainly a performance decision. If you render everything and just toggle visibility with CSS, the first render will take longer (but the time difference may not be relevant or even noticeable). If you render only the part that's visible, React needs to do a small rerender every time the sidebar content changes. (This may also not be noticeable time.)
My recommendation would be to try both, if you want to test the performance. But I think you won't go too wrong either way.
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'
}