Skip to content

Commit 6241fd1

Browse files
MichelMLwanjas
andauthored
fix: Incorrect useRef usage (with merged conflicts resolved) (#143)
* fix: Incorrect useRef usage * docs: percent can be an array * commit patched name * v3.3.3 * revert to rc-progress name to merge pack in original repo Co-authored-by: Ivan Belikov <[email protected]>
1 parent fc6ba0b commit 6241fd1

File tree

6 files changed

+80
-15
lines changed

6 files changed

+80
-15
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export default () => (
120120
</tr>
121121
<tr>
122122
<td>percent</td>
123-
<td>Number</td>
123+
<td>Number | Number[]</td>
124124
<td>0</td>
125125
<td>the percent of the progress</td>
126126
</tr>

docs/examples/gap.tsx

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { Circle, ProgressProps } from 'rc-progress';
33

4-
const colorMap = ['#3FC7FA', '#85D262', '#FE8C6A'];
4+
const colorMap = ['#3FC7FA', '#85D262', '#FE8C6A', '#FF5959', '#BC3FFA'];
55

66
function getColor(index) {
77
return colorMap[(index + colorMap.length) % colorMap.length];
@@ -13,8 +13,10 @@ class Example extends React.Component<ProgressProps, any> {
1313
this.state = {
1414
percent: 30,
1515
colorIndex: 0,
16+
subPathsCount: 3,
1617
};
1718
this.changeState = this.changeState.bind(this);
19+
this.changeCount = this.changeCount.bind(this);
1820
}
1921

2022
changeState() {
@@ -26,19 +28,38 @@ class Example extends React.Component<ProgressProps, any> {
2628
});
2729
}
2830

31+
changeCount() {
32+
this.setState({
33+
...this.state,
34+
subPathsCount: (this.state.subPathsCount % 6) + 1,
35+
});
36+
}
37+
2938
render() {
3039
const circleContainerStyle = {
3140
width: '200px',
3241
height: '200px',
3342
};
34-
const { percent, colorIndex } = this.state;
43+
const { percent, colorIndex, subPathsCount } = this.state;
3544
const color = getColor(colorIndex);
45+
46+
const multiPercentage = new Array(subPathsCount).fill(
47+
percent / subPathsCount,
48+
0,
49+
subPathsCount,
50+
);
51+
const multiPercentageStrokeColors = multiPercentage.map((v, index) => getColor(index));
52+
3653
return (
3754
<div>
3855
<p>
3956
<button type="button" onClick={this.changeState}>
4057
Change State [{percent}]
4158
</button>
59+
60+
<button type="button" onClick={this.changeCount}>
61+
Change Count [{subPathsCount}]
62+
</button>
4263
</p>
4364
<div style={circleContainerStyle}>
4465
<Circle
@@ -52,13 +73,13 @@ class Example extends React.Component<ProgressProps, any> {
5273
</div>
5374
<div style={circleContainerStyle}>
5475
<Circle
55-
percent={[percent / 3, percent / 3, percent / 3]}
76+
percent={multiPercentage}
5677
gapDegree={70}
5778
gapPosition="bottom"
5879
strokeWidth={6}
5980
trailWidth={6}
6081
strokeLinecap="round"
61-
strokeColor={[color, getColor(colorIndex + 1), getColor(colorIndex + 2)]}
82+
strokeColor={multiPercentageStrokeColors}
6283
/>
6384
</div>
6485

src/Circle.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const Circle: React.FC<ProgressProps> = ({
9696
const strokeColorList = toArray(strokeColor);
9797
const gradient = strokeColorList.find((color) => color && typeof color === 'object');
9898

99-
const [paths] = useTransitionDuration(percentList);
99+
const paths = useTransitionDuration();
100100

101101
const getStokeList = () => {
102102
let stackPtg = 0;
@@ -127,7 +127,14 @@ const Circle: React.FC<ProgressProps> = ({
127127
strokeWidth={strokeWidth}
128128
opacity={ptg === 0 ? 0 : 1}
129129
style={circleStyleForStack}
130-
ref={paths[index]}
130+
ref={(elem) => {
131+
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
132+
// React will call the ref callback with the DOM element when the component mounts,
133+
// and call it with `null` when it unmounts.
134+
// Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires.
135+
136+
paths[index] = elem;
137+
}}
131138
/>
132139
);
133140
})

src/Line.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const Line: React.FC<ProgressProps> = ({
2121
const percentList = Array.isArray(percent) ? percent : [percent];
2222
const strokeColorList = Array.isArray(strokeColor) ? strokeColor : [strokeColor];
2323

24-
const [paths] = useTransitionDuration(percentList);
24+
const paths = useTransitionDuration();
2525

2626
const center = strokeWidth / 2;
2727
const right = 100 - strokeWidth / 2;
@@ -76,7 +76,14 @@ const Line: React.FC<ProgressProps> = ({
7676
stroke={color as string}
7777
strokeWidth={strokeWidth}
7878
fillOpacity="0"
79-
ref={paths[index]}
79+
ref={(elem) => {
80+
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
81+
// React will call the ref callback with the DOM element when the component mounts,
82+
// and call it with `null` when it unmounts.
83+
// Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires.
84+
85+
paths[index] = elem;
86+
}}
8087
style={pathStyle}
8188
/>
8289
);

src/common.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ export const defaultProps: Partial<ProgressProps> = {
1414
gapPosition: 'bottom',
1515
};
1616

17-
export const useTransitionDuration = (percentList: number[]) => {
18-
// eslint-disable-next-line react-hooks/rules-of-hooks
19-
const paths = percentList.map(() => useRef());
17+
export const useTransitionDuration = (): SVGPathElement[] => {
18+
const pathsRef = useRef<SVGPathElement[]>([]);
2019
const prevTimeStamp = useRef(null);
20+
2121
useEffect(() => {
2222
const now = Date.now();
2323
let updated = false;
2424

25-
Object.keys(paths).forEach((key) => {
26-
const path = paths[key].current;
25+
pathsRef.current.forEach((path) => {
2726
if (!path) {
2827
return;
2928
}
29+
3030
updated = true;
3131
const pathStyle = path.style;
3232
pathStyle.transitionDuration = '.3s, .3s, .3s, .06s';
@@ -41,5 +41,5 @@ export const useTransitionDuration = (percentList: number[]) => {
4141
}
4242
});
4343

44-
return [paths];
44+
return pathsRef.current;
4545
};

tests/index.spec.js

+30
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,34 @@ describe('Progress', () => {
165165
expect(onClick).toHaveBeenCalledTimes(2);
166166
});
167167
});
168+
169+
it('should support percentage array changes', () => {
170+
class Demo extends React.Component {
171+
state = {
172+
subPathsCount: 2,
173+
};
174+
175+
render() {
176+
const { subPathsCount } = this.state;
177+
const percent = 80;
178+
const multiPercentage = new Array(subPathsCount).fill(
179+
percent / subPathsCount,
180+
0,
181+
subPathsCount,
182+
);
183+
184+
return (
185+
<>
186+
<Circle percent={multiPercentage} strokeWidth="1" />
187+
<Line percent={multiPercentage} strokeWidth="1" />
188+
</>
189+
);
190+
}
191+
}
192+
const circle = mount(<Demo />);
193+
expect(circle.find(Circle).props().percent).toEqual([40, 40]);
194+
circle.setState({ subPathsCount: 4 });
195+
expect(circle.find(Circle).props().percent).toEqual([20, 20, 20, 20]);
196+
circle.unmount();
197+
});
168198
});

0 commit comments

Comments
 (0)