I am new with react-spring. I am having trouble animating a component whenever it unmounts. I have a simple card with an onClick handler that's responsible for conditionally displaying my Overlay component. The animation works fine when mounting (from & enter works), but when closing the overlay, the component just disappears without animation (leave does not work). I suspect it's because of the conditional rendering of the component but I've been struggling for hours trying to find a solution for this one. Any help would be appreciated!
My current code: https://codesandbox.io/s/dry-leftpad-h3vmv
What I'm trying to achieve: https://codesandbox.io/s/048079xzw
P.S. The latter is using mauerwerk's lib. I don't want to use that.
What you were missing is this:
return expand.map(({ item, props, key }) => (
item && <animated.div
// ...etc
When you're controlling the mounting of a single component with useTransition, you need to conditionally render it based on the item being passed. In your case, when it's false it won't render (which will unmount if already mounted) and when it's true it will render (mount if unmounted).
Here's a working sandbox forked from yours: https://codesandbox.io/s/infallible-agnesi-cty5g.
A little more info
The first argument to useTransition is the list you want to transition. That watches for changes and sends back an array mapped with each item, a key and a style object (props) based on whether the item is truthy (entering) or falsy (leaving). So for a transition that mounts/unmounts a single element, conditionally rendering based on the truthiness of the item is key.
Check out the examples again here and you'll see the differences between transitioning a list, a toggle between two elements, and a single item.
For a list, no need to check for the existence of the item because the array changes.
For toggling between two elements, you use the truthiness of item to determine which element to render.
For a single element, item determines whether to render at all. This means it won't mount initially when you default to false, and will make sure you don't render 2 items whenever your isActive value changes.
Related
I'm making a to-do list type app to learn React. I have an App component, which contains a Todolist component, which contains ListItem components. Each ListItem component has a title and a boolean completed which is controlled by a checkbox.
ListItem components that are checked and completed are sorted to the bottom of the Todolist. When an item is checked, I call a function setItemCompleted() (passed down in props from App) to update App's state and re-render everything.
In setItemCompleted() I print the updated array of ListItem and it matches what I expect it to be. When React re-renders everything and I open the Chrome inspector to check the rendered HTML, it also matches what I expect it to be. The problem is, the actual ListItem that are displayed on the page do not match either of these; instead of the checked off item moving to the bottom of the page, the last item in the list gets checked.
Here is a "minimal, complete, and reproducible" example:
https://codesandbox.io/s/react-playground-su7iw?file=/index.js
You use index as ListItem key which is not recommended and in your case causes these issues. Change from key={i} to key={item.itemID} and it should fix these issues.
Been hacking at this for days, hopefully there are some Vuetify wizards around.
Here's the situation: I have rendered a set of v-expansion-panels and if one of them is expanded, it also shows an arrow button (display: none is toggled by clicking on v-expansion-header). Upon that button click, my aim is to show a dialog.
Problem: Once dialog is prompted with the button click, the button display toggle is reversed. It disappears as soon as you click on the button to prompt a dialog, and appears again once the v-expansion-panel is collapsed.
How it should be: The arrow button should always be visible as long as the v-expansion-panel is expanded, regardless of whether it is clicked to see the dialog or not.
Here's a codepen replicating and illustrating the problem.
Any thoughts would be much appreciated!
It has to do with using style directly on the element.
Use v-show instead of toggling the styles by hand:
<v-btn v-on="on" class="ml-1" width="36px" v-show="expanded[i]">
Update your data to hold an array for the pannels
data () {
return {
dialog: false,
expanded: [false, false, false]
}
}
And update your toggleMoveUp method to update expanded instead of using HTML ids.
toggleMoveup(i) {
this.$set(this.expanded, i, !this.expanded[i])
this.show=true;
}
Notes:
You need to use Vue.set when updating an array
You should not rely on HTML ids, if you use your components in more than one place at a time you'll run into multiple ids.
Why didn't your approach work? I'm guessing that vuetify is updating an element's style property, but doesn't take care of retaining already existing values so your display:none gets erased.
Posting a solution a colleague helped with. This also works with any array size (which is more of a real life scenario in dynamic webapps). It implements a created() lifecycle hook that adds an expanded: false property to each element in the array, which we can use to keep track of the expand state and toggle the button visibility. Here's the codepen.
However, in general, it is recommended in this scenario to actually make an independent component <v-expansion-panels /> and in the parent component actually loop the components. That would solve the state problems on its own already, since each component maintains their own state in their scope.
I have angular component, which is loading other components , now in a event change say dropdown item selection, i need to reload just one specific component. Is it Possible to do that?
I looked into some answers in stack overflow itself but mostly are about reloading the whole page.
<dropdown (change)="detectChange($value)" />
<Component-one></Component-one>
In one component i have a 'drop down' with few values, and other component say 'component-one' already loaded with it , when the value in the "dropdown" changes i need to reload "component-one".
It is a general question. First of all you need to understand what you want to achieve in the end.
One way for "reloading" component, pass some data to the component based on the dropdown value, so, it will automatically "reload".
The other way is that you can have url param or query param based on the dropdown value, and on dropdown value change, navigate to the route with new param value, so the component will "reload".
I have a list of items (ResultItem), which have a component inside (ResultTag) which when clicked, shows a tooltip above it (a HTML class is added to it and removed when clicked again, to hide it).
However, when I click on ResultTag, and then click on ResultTag in one of the ResultItem's below it, both show; how would I go about hiding all of the ResultTag's apart from the one I just clicked on, so that only one can show at a time.
Currently, in the ResultItem, I have an onClick function which sets the state showTooltip in the ResultTag to false/hidden (using props) whenever the user clicks anywhere within ResultItem and the ResultTag is visible. However, I need this to work across every ResultItem, which means working cross-component.
Here is some simplified code:
/* ResultTag */
showTooltip() {
this.setState({ showTooltip: true })
}
render() {
return (
<div onClick={this.showTooltip}>
{this.renderTooltip()} { /* function which contains the JSX/HTML to show the toolip */ }
<span className="tag--label">Tags</span>
</div>
)
}
Hiding is done in the ResultItem, by setting the state and then receiving that as props in the ResultTag.
To summarise:
I have many ResultItem components in a list view
Each ResultItem has a ResultTag in, which when clicked, shows a tooltip above the tag/label
When a ResultTag is visible, and another one in a different ResultItem is clicked, hide all the other ResultTags
You could move the state from within each individual ResultItem into the parent, that way it is centralized in one place and you could enforce logic such that only a certain ResultItem will show its tooltip. You would need to manage the state from within the parent and then pass down a function to each ResultItem (and probably down again into its ResultTag) to handle the click.
I wrote a sample app which shows similar behaviour (although slightly different), I wrote it to demonstrate how to add a border to each item in a list. You can see how I stored the state in the parent and how I passed down the means to read and update it to the children via props. You would of course have to change the logic to enforce only a single item being active, currently it supports any item in the list being 'active'. I wrote it for an answer located here: https://stackoverflow.com/a/38646533/1515758
I have an array of JSON objects that are used to render a list of elements:
mydata.map(thing => {
return <SomeComponent key={thing._id} />
});
Each rendered item has up/down arrows, and if the user clicks the up arrow, for example, the item will be moved up the list. On the back end, the items in the array are simply swapped.
How can I make this process animate so it's easier for the user to see what the result of their action was? I was looking into react-motion, but it seems to work based on modifying CSS/styles. I was hoping there would be something that uses React's key property to determine unique elements and handle movement based on that.
Any suggestions?
React-flip-move is a wonderful component which allows you to animate children components. There is an example animation flipping values on a list too.