PJCHENder 未整理筆記

[React] React Snippets

2019-02-15

[React] React Snippets

@(React)[React, snippet]

Cancel Button with React Router

1
2
3
4
<!-- 使用 withRouter 後即有 history 可用 -->
<CancelButton htmlType="button" className="mr-10px" onClick={() => history.goBack()}>
Cancel
</CancelButton>

Split String Into Component

keywords: split, parse, react component, string

根據正規式把字串轉換成 React Component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const parseTime = text => {
const pattern = /\b(\d{2}:\d{2})\b/g;
const splitText = text.split(pattern);

if (splitText.length <= 1) {
return text;
}

const matches = text.match(pattern);
const newContent = splitText.reduce((arr, element) => {
if (!element) return arr;

if (matches.includes(element)) {
return [...arr, <Component />];
}

return [...arr, element];
}, []);

return newContent;
};

Spinner Component

The design is credits by Fran Pérez @ CodePen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import React from 'react';
import styled, { keyframes } from 'styled-components';

const offset = 187;
const duration = '1.4s';

const rotator = keyframes`
0% { transform: rotate(0deg); }
100% { transform: rotate(270deg); }
`;

const colors = keyframes`
0% { stroke: #4285F4; }
25% { stroke: #DE3E35; }
50% { stroke: #F7C223; }
75% { stroke: #1B9A59; }
100% { stroke: #4285F4; }
`;

const dash = keyframes`
0% { stroke-dashoffset: ${offset}; }
50% {
stroke-dashoffset: ${parseInt(offset) / 4};
transform:rotate(135deg);
}
100% {
stroke-dashoffset: ${offset};
transform:rotate(450deg);
}
`;

const StyledSVG = styled.svg`
animation: ${rotator} ${duration} linear infinite;

.path {
stroke-dasharray: ${offset};
stroke-dashoffset: 0;
transform-origin: center;
animation: ${dash} ${duration} ease-in-out infinite,
${colors} ${parseInt(duration) * 4}s ease-in-out infinite;
}
`;

const Spinner = () => {
return (
<StyledSVG
width="65px"
height="65px"
viewBox="0 0 66 66"
xmlns="http://www.w3.org/2000/svg"
>
<circle
className="path"
fill="none"
strokeWidth="6"
strokeLinecap="round"
cx="33"
cy="33"
r="30"
></circle>
</StyledSVG>
);
};

export default Spinner;

isUnmounted 判斷

如果碰到這種問題,可以在 component 中多一個靜態的變數(不是會變動的 state),例 isUnmounted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const ReactComponent = () => {
const [data, setData] = useState();
let isUnmounted = false;

useEffect(() => {
const fetchData = async () => {
const data = await fetch('foobar');

// ⚠️ 問題可能出在這!
// 有可能 fetch 到 data 的時候,這個 Component 已經不存在了
// 因此要確認該 component 還沒 unmounted 的時候才能執行 setState
if (!isUnmounted) {
setData(data);
}
};

fetchData();

return () => {
isUnmounted = true;
};
}, []);
return <h1>react component</h1>;
};

也可以使用 useRef

使用 useRef 的差別主要在於,當這個 component 重新 render 的時候,可以取得上一次重新 render 的狀態,但在這裡每次都會把 isUnmounted 設回 false,所以兩種方式應該都可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const ReactComponent = () => {
const [data, setData] = useState();
const isUnmounted = useRef(false);

useEffect(() => {
const fetchData = async () => {
const data = await fetch('foobar');

// ⚠️ 問題可能出在這!
// 有可能 fetch 到 data 的時候,這個 Component 已經不存在了
// 因此要確認該 component 還沒 unmounted 的時候才能執行 setState
if (!isUnmounted.current) {
setData(data);
}
};

fetchData();

return () => {
isUnmounted.current = true;
};
}, []);
return <h1>react component</h1>;
};
Tags: snippet

掃描二維條碼,分享此文章