I am attempting to create an easy-to-use UI/UX selection system.
Essentially, on the viewport, I first have 3 "difficulty" components that choose what "difficulty level" you want.
Once clicked, they should then transition to the next selection phase, which would be "male" or "female".
Clicking this button should move/remove the difficulty level component to the left (out of the viewport), and move the sex selection into the viewport.
How would I implement this?
I also plan on implementing a "Go back" feature as well in the future, so that users can go back and forth from Difficulty and Sex components.
My ideas
Once the button is clicked, I just use CSS to transition the difficulty component out of the viewport, and the "sex" component into the viewport. After the transition, I give that component a display: none to remove it completely from the user.
Concerns: This doesn't seem efficient. Should I be removing the component entirely? If so, where does one begin to do that?
Another method would be to remove/add the components as needed...which I believe would require using the ComponentDidMount() and ComponentDidUnmount() functions, and then using the React Transition Group library to somehow transition them out?
Here is an excellent, Picasso-like, hand-drawn example from myself:
There is how to do the transition.
Typically, setting display: none stops any sort of animation, which you don't want to do.
export default class Modal extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.show !== this.props.show ||
nextProps.children !== this.props.children
);
}
render() {
const { show, children } = this.props;
return (
<div
style={{
transform: show ? 'translateY(0)' : 'translateY(-100vh)',
opacity: show ? 1 : 0,
}}
>
{children}
</div>
);
}
}
Note that returning false from shouldComponentUpdate will stop re-rendering the modal and its children.
The children could be anything or nothing. So when you don't want to show it, render an empty div outside view window is very efficient.
Key takeaway
display: none shouldn't need most of the time. It doesn't support animation, and render function can return <div /> or null.
React components will re-render when received new props or updated state, regardless display type and window position.
Mare sure have a clear understanding on rendering lifecycle, not all mounting/updating functions can setState, and you can stop re-rendering manually.
Related
I'm building a carousel in react. The carousel is passed an array of slides and these are cloned as needed depending on how many slides must be shown. This is useful for infinite scrolling for example, where the width of the screen may require more slides than the ones I'm passing to the component. As an example, I can pass 3 slides to the carousel but because the user zoomed out a lot, 10 slides fit the total width, so 10 slides are shown that are just copies of that 3 initial slides.
The main problem I am facing is that when I need to build the cloned slides, I first need the parent component width to know how many I should be creating. The reference to the component at this time hasn't been yet resolved so I can't use it and modify the DOM in the useEffect or useEffectLayout seems not to be the way to go with react. So, how could I get around this?
This is how I use the carousel:
<Carrousel startingSlide={0}>
{
productData.slice(0,slidesCount).map( (o, index)=>{
let key = "slide-content-"+index;
return <div key={key} id={key} className="carousel-item">{o.title}</div>
})
}
</Carrousel>
And here how the carousel tries to build the needed cloned slides when rendering:
return (
<section className="carrousel-container" ref={containerRef}>
{
children.length ? buildSliderElementsForWidth("HERE I NEED THE CONTAINER WIDTH") : "NO DATA"
}
</section>
);
I'm struggling to use CSS Keyframes with React.
I can get them to work when the component is mounted but when the component is unmounted the CSS transitions don't get a chance to animate before the state removes it from the DOM.
I'm not keen on doing this with a JS library when it feels like there should be a way to do this with good old CSS.
I've got a codepen that I put together to show what I've got so far.
https://codesandbox.io/s/react-hooks-usestate-forked-dhvu7?file=/src/styles.css
At the end of the animation I'd like the component to be unmounted I don't want it to stay in the dom.
Thanks in advance.
You can use css keyframe and use onAnimationEnd event handler to trigger state change after the animation is finished. Also you can add style={{ animationFillMode: "forwards" }} to the node to preserve the CSS properties of the last keyframe before removing it from the DOM.
Example:
{removeDom && (<button
style={{ animationFillMode: "forwards" }}
className="some animation class"
onAnimationEnd={()=>setRemoveDom(true)}
/>)}
For anyone else wanting a solution this article got me to where I wanted to be
https://czaplinski.io/blog/super-easy-animation-with-react-hooks/
Scenario
I'm working on a ReactJS project that has a lot of re-used components on the page, so many components that it causes some of the css animations to become sluggish. I've found that if I use display:none on components below the page fold that my performance bottlenecks vanish.
Question
Is there a currently library, or a very simple way to accomplish this? Worst case I will write a library for this and put it on github.
Caveats
Using display:none gives an element 0 width / height so I'll need to use a placeholder of an assumed size.
I will "unrender" visible components once they go out of the visible window area
lazy loading libs didn't pan out like I hoped, LazyLoadJS is the most promising and what I would leverage if I ultimately need to write my own solution
My situation is rather unique but I'll break it down to relevant pieces as much as I can:
My application is a ReactJS SPA or Single Page Application (so lots of xhr, async loading)
Using the same scroll area for the entire life cycle (.content-group)
Json from the CMS includes component names and respective data. My "SomeFactory" (not the real name) gets the mapped component name and renders the component to the factory container.
Some Caveats:
forceCheck is what made this work, it reassess where lazy items are within the scroll container
overflow was helpful since I'm using overflow: hidden as part of this element's ancestry.
Code
import LazyLoad, { forceCheck } from 'react-lazyload';
class LazyLoadOptimized extends React.Component {
render() {
return (
<LazyLoad throttle={50} height={200} offset={400} overflow scrollContainer={'.content-group'}>
{this.props.children}
</LazyLoad>
)
}
}
export default class SomeFactory extends Component {
componentDidUpdate() {
forceCheck();
}
}
I'm developing a numerical Slider component in React. It actually works right now and is fully functional, but there is a single issue. I set the width of the thumb and total slider via CSS, and I like doing it that way, as it's flexible.
The slider and thumb width is also needed for calculations, such as calculating the max position of the slider, or the position of the thumb relative to the absolute.
So, I have functions like this:
getSliderWidth = () => {
return this.sliderRef.current ? this.sliderRef.current.offsetWidth : 0;
}
getThumbWidth = () => {
return this.sliderThumbRef.current ? this.sliderThumbRef.current.clientWidth : 0;
}
Where the refs are defined in the render function like so:
<div ref={this.sliderRef} className="slider-range">
<div className="slider-range-connect" style={connectStyle}></div>
<div ref={this.sliderThumbRef} className="slider-range-thumb" style={thumbStyle}></div>
</div>
The issue with this, though, is that the widths are only known after the first render. The refs aren't available until it is first rendered. So, I think what I need to do is force a re-render, such that when the component is initially loaded, it is rendered one more time. This is because the initial render function needs to know the relative max position and thumb position in order to render the initial elements.
So, is there a "React" way to do this, or am I missing something? Is the ideal solution here to have some sort of boolean flag, and in the initial mount function, to check this flag, and if it is the first render, to do another render, and then to set the flag? That doesn't seem very "React"ish, so I was wondering if there is something more elegant.
Let's say we have this block of code:
<View>
<Image
source={{uri: this.props.image}}
renderIndicator={() => <SimpleLoader />}
/>
<Text>{this.props.title}</Text>
</View>
It currently shows a rendering animation on the image, but shows the View as well as text, and then eventually renders the image.
I would like to:
1) Have the View itself have <SimpleLoader /> be displayed while any child item is rendering
2) identify when all the children have finished rendering (or the image, in particular), and then fade the view in.
I was reading around on potentially using a callback with componentDidMount but I'm not entirely sure how to achieve this.
An easy way would be to use react-native-image-progress
One way to do it manually would be to have a loaded: false property in the state initially, then set the onLoad prop of Image to a function that calls setState({loaded: true}). Then create a function, say showImage() that returns a view of either the image, or the loading indicator depending on whether state.loaded is true or false respectively. In render(), you can then call {this.showImage()}
To fade the image, you can use Animated to animate the opacity of the image inside the style from 0 to 1.