So I've looked at the react springs docs, and I'm sure I'm just not understanding it properly. But I wanted to essentially try to make a div have an enter animation and some kind of trigger to make it leave
I have been unsuccessful in triggering this leave. I can't seem to understand what makes it trigger the leave functionality. Or maybe I'm just not understanding the transition in general which is entirely possible.
The idea is simple, I want to be able to trigger something to come into view, and then when something else happens, to trigger it to go out of view.
I took an example from the react-spring docs, and made my own fork, to demonstrate what I seem to be misunderstanding.
If you go to this codepen, and click anywhere in the display box, you'll notice some animation happening. From my understanding, the state variable isTrue should be telling the transition what state to be in. So if it's false, I would assume this would trigger leave. But it doesnt leave, as you can see from the example, it stays at the enter rule (display being block and opacity being 1).
Essentially, I'd want it to come into view initially, and when i click on it, to trigger the leave rule and have it animate out to display none and opacity 0.
Any help is appreciated.
Transition basic function is for displaying the content of an array. If you manipulate the array the transition will follow. You can add, insert and delete elements and react spring will take care the animation of each item.
When you use transition to switch on/of a single item with a boolean value. You have to modify your render method to add an extra condition ( item &&) in front of your component. As you can see in the last example here: https://www.react-spring.io/docs/hooks/use-transition
{transitions.map(({ item, props, key }) => {
const Page = pages[0]
return item && <Page key={key} style={props} />
})}
This is the modified code:
https://codesandbox.io/s/xenodochial-buck-k40bj
Related
I am trying to use a parent component to control animations in a child Canvas element. Specifically I want an animation to happen when a user inputs a correct answer.
It works until the user changes the state in the parent component, and then it no longer works.
I've made a stripped-back, minimal version of my code here to show my issue: https://codesandbox.io/s/epic-leaf-08jqvy?file=/src/App.js
My desired behaviour is that the red box bounces when a user clicks submit. That happens if they don't type anything in the input box, but as soon as you enter anything into there - changing state and re-rendering the component - the button no longer triggers the animation in the Canvas child component.
As far as I can tell, the issue is to do with changing the state when inputing text. If I make a version where the input is just assigned to a variable, it works fine, but I need to be able to use state and re-render other parts of it.
I have put a console.log in the jump() function, so I can see that it is being called, but no animation is taking place in the canvas.
I assume that what's happening is that everything is being re-rendered when the state changes, and so the useRef is no longer tracking to the right thing.
Things I've tried:
putting the canvas in a memoized component to prevent it from re-rendering
using eventlisteners to see if I can trigger the animations in other ways - keydown ones work, but I need the user to be able to type, so I tried other ones (like hashchange or audio.play) but neither of those worked.
You can see the thing I'm actually trying to build here: https://papaya-platypus-86565f.netlify.app/play Basically users answer questions and an animation plays depending on whether they're right or wrong, to give it a game-y feel.
Thanks!
I like your red box as well as your reasoning. Yes, the input state changing on keystroke is causing the entire App component to re-render. Note that your App.js component has a lot going on (all good stuff), such as your Box class instantiation, your canvas instantiation, etc.
The key is to break your components into smaller parts, particularly separating stateful components from non-stateful components. We don't want your canvas re-mounting on every input change, so we make them sibling components!
Here's a working example of your code, just in smaller components:
https://codesandbox.io/s/strange-julien-d3n4zm
I hope this helps.
I want to build a simple app like in picture attached with react js, I just cannot find the right idea of:
How to "select" photos(or item) in an application and have the "cart"-like component appear at the bottom when at least one photo/item is selected(and close and deselect all already selected photo/items) and expand the cart-like component at the bottom when clicked to show what's been already selected.
What is the best approach to this?
P.S I'm new to react with a big idea in mind xD
app's view
This question definitely needs more information, but I will try to point you in the right direction. There are hundred of ways to create the UI/functionality you are describing but here is a very generic overview;
The "items" (Img1-6) looks like a grid of ShopItem components, possibly in a CSS Grid / flexbox. Each ShopItem would probably make use of an onClick method to "do something" when it is clicked - this may involve updating a state (using the useState react hook) somewhere which tells you if a ShopItem is checked or not. It could also potentially use a callback method to do something in the parent when the items are checked.
I imagine that each ShopItem may own its own "checked" state or may update a global state (Such as Zustand or Redux) or a Context (React) when it is toggled on and off. The checked state of a ShopItem would also inform the UI of the component.
The "cart-like" component could be looking at the global state/context/callback from the item component, and could change based on its value and how many checked items there are. (Eg/ checkedItems !== 0 ? show : don't show)
This is just one way in which this UI can be built, if you would like a more specific solution, please edit your question to include code snippets and what you've already tried.
The Scenario
I am using the Reactour library to create a guided tutorial on my website. The library allows me to interact with highlighted components, which is the desired behavior. However, my input boxes have a onBlur attribute that updates the state in a parent component, thus re-rendering the child (component where the input boxes are).
The Issue
The problem is that this re-render is messing up the focus and the user is not able to "tab" between fields (when the tutorial is open). It seems that the Reactour component is receiving the focus after the re-render, even though they have a tabIndex="-1" set by default in their component.
My Approach
I tried to set explicit tabIndex properties, but that didn't work.
I thought about having an onKeyDown listener, check if the pressed key is tab and "manually" control the focus between fields, but that seems too hacky and messy, considering I have a lot of fields in my form.
I made a CodeSandbox here to reproduce the bug. You will notice that you can tab between inputs when the Tutorial is closed, but clicking the "Start Tour" button will mess the tabIndex behavior.
Any ideas?
Just for reference, this seems to be an issue with Reactour and it was logged here. Hopefully, it will be fixed soon.
For now, as a workaround, my solution was to manually set the tabIndex of Reactour components during initialization:
setTimeout(() => {
const elements = document.querySelectorAll("#___reactour button");
elements.forEach((el) => (el.tabIndex = -1));
}, 100);
The timeout is necessary since it takes a little bit for the elements to show up in the screen.
This Is more of a "theoretical" question that often buffles me in different situations and use cases, I will give a simple example to demonstrate it.
Let's say I have a list of 10 buttons.
Everrytime I click a button, a floating menu appears on top of the clicked button - there is only one menu visible for any given time.
Let's assume that I can't render this floating menu within the button component and I can only render it in the buttons parent level (meaning that this menu is sibling to those buttons).
I have 2 possible options to do that:
Keep the x,y position of the last clicked button and render the menu in this given position
Render the menu once and using "ref" to directly relocate the menu
On the one hand, the first approach seems more "Reactish". On the other hand, the possible implemention I can think of is pretty ugly (capturing the clicked item position and saving it to state which triggers defender), and further more, I am not so sure about re re rendering the whole container just because I need to move a small piece of it.
The second approach touches the DOM directly using refs. Although possible , doing DOM manipulations sometimes feel bad to me.
Is there a better approach? Which of the 2 makes more sense?
Any suggestion or thoughts will be appreciated!
Thanks
React uses whats called a virtual DOM, which is a representation of the DOM, that sits on top of the real browser DOM. Whenever you update state or a user performs an action the virtual DOM compares and checks the changes with the real DOM and then updates the UI accordingly.
So if certain DOM elements like a are not different between changes it does not get re rendered, only the DOM elements that have changed are re rendered. And if a property on a DOM element is changed, only the property is updated and the DOM element is not re rendered.
<div color="blue" />
to
<div color="red" />
The whole element is not destroyed and re created, only the property is changed.
However if the element in the host tree is different than the entire host tree is destroyed and recreated.
<div />
to
<p>
This is refereed to as reconciliation
https://reactjs.org/docs/reconciliation.html
So using refs is definitely more of a hacky solution since its more of an escape hatch and directly manipulates the DOM.
I would definitely stick with option 1, I think there is an elegant solution to the use case you described, it would involve just adding a click event listener in the componentDidMount and keeping track of the click position that way.
And also its hard to say without code but since your buttons will be the same, they will not be re rendered only the menu will.
Would recommend for further reading
https://overreacted.io/react-as-a-ui-runtime/
I have a scenario where I can't use scrollview or flatlist.
UI is kind of wizard when press next I move user to next screen or previous on back.
In render function I have:
<View style={{flex: 1}}>
<WizardItem data={this.props.currentStep} />
</View>
Component WizardItem has button inside which update this.props.currentStep and when it is updated in reducer it is naturally updated here.
But I need to animate transition like current step goes left and new come from right and vice versa.
As you can see step is completely dynamic so I can't load it in lists as I don't know until user press next button what is next item.
But I need that animation.
Can somebody guide me on how to do this effect or I should stop thinking about it if it is not possible?
UPDATE
Bellow is example of something similar just no rotation simple move left right.
But I can't use views where I have list of items predefined as next and previous step in wizard are dynamic.
enter link description here
If I understand it correctly you want that to transition to a different screen. To do this I suggest you use LayoutAnimation in React Native. LayoutAnimation lets you animate state changes instead of things simply disappearing and appearing. You can save the currentStep in state instead of props and every time the state changes use LayoutAnimation to transition in the way you want.
This article uses layout animation for screen transitions
If changing to state from props is something that you cannot do or don't want to do, you could also detect prop changes in your Wizard and then use Animated to move your layouts around.
It's tricky to suggest a best way without knowing how Wizard is setup or at the least its general layout. If it is possible to share some code for Wizard it would be easier to help you.