Skip to main content

[react] Snippets

Cancel Button with React Router#

<!-- 使用 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:

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

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

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,所以兩種方式應該都可以。

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>;
};
Last updated on