The React project I recently worked on required such a component to display data.
This is actually quite simple. With normal react programming thinking, I simply calculate its width dynamically according to the data and generate corresponding nodes in a loop. Some of the core React code is as follows
{data && data.length > 0
? data.map((item, index) => (
<div className={styles.item} key={index}>
<div className={styles.itemTop}>
<span>{item.label}</span>
<span className={styles.num}>{item.value}</span>
</div>
<p className={styles.progressBar}>
<span
className={styles.inner}
style={{ background, width: getWidth(item.value)}
/>
</p>
</div>
))
: null}
Copy the code
This will do the function shown above, but now there is a requirement that the blue bar move as soon as it is loaded.
transition
The first one, of course, is the transition property of the CSS, and then you add it to your code
.inner { width: 0; 0.6 s help ease the transition: width; }Copy the code
It was all so simple, but the animation didn’t work.
And THEN I went back and thought why didn’t it work?
The transition property only works if the width property is changed. All that can be said is that the width of the span has not changed. This brings me to my code, which computes the width and renders the node at the same time, meaning that the width of the node is already set when it is generated. So of course transition is not going to work
Now how can I improve this code to make the animation work?
I’ll just have to get the node generated and then change its width.
This brings to mind the Ref property in React, which takes a string or a function that fires when a node is loaded or destroyed. Once the SPAN node is rendered, I can manipulate the actual DOM node returned by this function to change its width, which is exactly what I need.
With an idea in mind, I started to improve the code.
{data && data.length > 0
? data.map((item, index) => (
<div className={styles.item} key={index}>
<div className={styles.itemTop}>
<span>{item.label}</span>
<span className={styles.num}>{item.value}</span>
</div>
<p className={styles.progressBar}>
<span
className={styles.inner}
style={{ background }}
ref={n => {
if (n && n.style) {
n.style.width = `${getWidth(item.value)}px`;
}
}}
/>
</p>
</div>
))
: null}
Copy the code
Then open the browser to see the result, sure enough, success. The effect is as follows.