1. Problem1
```typescript=
import { useEffect, useState } from "react";
function getResult(count: number) {
return new Promise<number>((resolve) => {
const timeout = Math.floor(Math.random() * 1000);
const timer = setTimeout(() => {
resolve(count);
clearTimeout(timer);
}, timeout);
});
}
function useResult() {
const [count, setCount] = useState<number>(0);
const [result, setResult] = useState<number | "loading">(0);
useEffect(() => {
setResult("loading");
getResult(count).then(setResult);
}, [count]);
return [count, setCount, result] as const;
}
export default useResult;
```
2. Problem2
```typescript=
const STATE = {
AL: "AL", // Alabama
AK: "AK", // Alaska
AZ: "AZ", // Arizona
AR: "AR", // Arkansas
};
const STATE_DATA = {
POST_CODE: {
[STATE.AL]: "01",
[STATE.AK]: "02",
[STATE.AZ]: "03",
[STATE.AR]: "04",
},
AREA: {
[STATE.AL]: 100,
[STATE.AK]: 200,
[STATE.AZ]: 300,
[STATE.AR]: 400,
},
CITIES: {
[STATE.AL]: ["city 1", "city 2"],
[STATE.AK]: ["city 3", "city 4"],
[STATE.AZ]: ["city 5", "city 6"],
[STATE.AR]: ["city 7", "city 8"],
},
};
function getStateData<T>(data: { [x: string]: T; }, state: string): T {
return data[state];
}
// Here are some use case.
// the editor may be able to infer code as type of string
const code = getStateData<string>(STATE_DATA.POST_CODE, STATE.AL);
// the editor may be able to infer area as type of number
const area = getStateData<number>(STATE_DATA.AREA, STATE.AL);
// the editor may be able to infer cities as type of an array of numbers
const cities = getStateData<string[]>(STATE_DATA.CITIES, STATE.AZ);
```
3. Problem3
```typescript=
enum KeyType {
Number = 1,
DOT = 2,
Operator = 3,
Clear = 4,
Equal = 5,
}
enum StateType {
Start = 1,
FirstArg = 2,
FirstArgFloat = 3,
Operator = 4,
SecondArg = 5,
SecondArgFloat = 6,
SecondArgDot = 7,
Equal = 8,
}
function getNextStateType(key: KeyType, previousStateType: StateType): StateType {
switch (previousStateType) {
case StateType.Start:
if (key === KeyType.Number) {
return StateType.FirstArg;
}
if (key === KeyType.DOT) {
return StateType.FirstArgFloat;
}
break;
case StateType.FirstArg:
if (key === KeyType.Number) {
return StateType.FirstArg;
}
if (key === KeyType.Operator) {
return StateType.Operator;
}
if (key === KeyType.DOT) {
return StateType.FirstArgFloat;
}
if (key === KeyType.Clear) {
return StateType.Start;
}
break;
case StateType.FirstArgFloat:
if (key === KeyType.Number) {
return StateType.FirstArgFloat;
}
if (key === KeyType.Operator) {
return StateType.Operator;
}
if (key === KeyType.Clear) {
return StateType.Start;
}
break;
case StateType.Operator:
if (key === KeyType.Number) {
return StateType.SecondArg;
}
if (key === KeyType.DOT) {
return StateType.SecondArgDot;
}
break;
case StateType.SecondArg:
if (key === KeyType.DOT) {
return StateType.SecondArgFloat;
}
if (key === KeyType.Number) {
return StateType.SecondArg;
}
if (key === KeyType.Equal) {
return StateType.Equal;
}
if (key === KeyType.Operator) {
return StateType.Operator;
}
if (key === KeyType.Clear) {
return StateType.Operator;
}
break;
case StateType.SecondArgFloat:
if (key === KeyType.Number) {
return StateType.SecondArgFloat;
}
if (key === KeyType.Equal) {
return StateType.Equal;
}
if (key === KeyType.Operator) {
return StateType.Operator;
}
if (key === KeyType.Clear) {
return StateType.Operator;
}
break;
case StateType.SecondArgDot:
if (key === KeyType.Number) {
return StateType.SecondArgFloat;
}
if (key === KeyType.Clear) {
return StateType.Operator;
}
break;
case StateType.Equal:
if (key === KeyType.Equal) {
return StateType.Equal;
}
if (key === KeyType.Number) {
return StateType.FirstArg;
}
if (key === KeyType.Operator) {
return StateType.Operator;
}
if (key === KeyType.DOT) {
return StateType.FirstArgFloat;
}
break;
}
}
```
4. Problem4
index.tsx
```typescript=
import * as React from "react";
import { createRoot } from 'react-dom/client';
import { App } from "./App";
const container: any = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals()
```
App.tsx
```typescript=
import { ChakraProvider } from "@chakra-ui/react";
import { DAppProvider } from "@usedapp/core"
import theme from "./theme";
import Header from "./components/Header";
import TransferringEthers from "./pages/transferringEthers";
export const App = () => {
return (
<DAppProvider config={{}}>
<ChakraProvider theme={theme}>
<Header />
<TransferringEthers />
</ChakraProvider>
</DAppProvider>
);
}
```
主题 index.tsx
```typescript=
import { extendTheme } from "@chakra-ui/react";
export default extendTheme({
fonts: {
initialColorMode: "light",
useSystemColorMode: false
},
});
```
Identicon index.tsx
```typescript=
import { useEffect, useRef } from "react";
import { useEthers } from "@usedapp/core";
import Jazzicon from "@metamask/jazzicon";
import styled from "@emotion/styled";
const StyledIdenticon = styled.div`
height: 1rem;
width: 1rem;
border-radius: 1.125rem;
background-color: black;
`;
export default function Identicon() {
const ref = useRef<HTMLDivElement>();
const { account } = useEthers();
useEffect(() => {
if (account && ref.current) {
ref.current.innerHTML = "";
ref.current.appendChild(Jazzicon(16, parseInt(account.slice(2, 10), 16)));
}
}, [account]);
return <StyledIdenticon ref={ref as any} />;
}
```
Header index.tsx
```typescript=
import {
Spacer,
Box,
Flex,
useDisclosure,
HStack
} from "@chakra-ui/react";
import ConnectButton from "../ConnectButton";
import ModalAccount from "../ModalAccount";
import { ColorModeSwitcher } from "../../ColorModeSwitcher";
function Header() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<Flex width="90%" margin="auto" p="4" minWidth="500px">
<Spacer />
<HStack>
<Box>
<ConnectButton handleOpenModal={onOpen} />
{isOpen && <ModalAccount isOpen={isOpen} onClose={onClose} />}
</Box>
<Box>
<ColorModeSwitcher justifySelf="flex-end" />
</Box>
</HStack>
</Flex>
);
}
export default Header;
```
ModalAccount index.tsx
```typescript=
import {
Box,
Button,
Flex,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
Text,
} from "@chakra-ui/react";
import { useEthers } from "@usedapp/core";
import Identicon from "../Identicon";
type Props = {
isOpen: any;
onClose: any;
};
export default function ModalAccount({ isOpen, onClose }: Props) {
const { account, deactivate } = useEthers();
function handleDeactivateAccount() {
deactivate();
onClose();
}
return (
<Modal isOpen={isOpen} onClose={onClose} isCentered size="md">
<ModalOverlay />
<ModalContent
background="gray.900"
border="1px"
borderStyle="solid"
borderColor="gray.700"
borderRadius="3xl"
>
<ModalHeader color="white" px={4} fontSize="lg" fontWeight="medium">
账户
</ModalHeader>
<ModalCloseButton
color="white"
fontSize="sm"
_hover={{
color: "whiteAlpha.700",
}}
/>
<ModalBody pt={0} px={4}>
<Box
borderRadius="3xl"
border="1px"
borderStyle="solid"
borderColor="gray.600"
px={5}
pt={4}
pb={2}
mb={3}
>
<Flex justifyContent="space-between" alignItems="center" mb={3}>
<Text color="gray.400" fontSize="sm">
MetaMask
</Text>
<Button
variant="outline"
size="sm"
borderColor="blue.800"
borderRadius="3xl"
color="blue.500"
fontSize="13px"
fontWeight="normal"
px={2}
height="26px"
_hover={{
background: "none",
borderColor: "blue.300",
textDecoration: "underline",
}}
onClick={handleDeactivateAccount}
>
更改
</Button>
</Flex>
<Flex alignItems="center" mt={2} mb={4} lineHeight={1}>
<Identicon />
<Text
color="white"
fontSize="xl"
fontWeight="semibold"
ml="2"
lineHeight="1.1"
>
{`${account?.slice(0, 6)}...${account?.slice(
account?.length - 4,
account?.length
)}`}
</Text>
</Flex>
</Box>
</ModalBody>
</ModalContent>
</Modal>
);
}
```
连接钱包 index.tsx
```typescript=
import { Button, Box, Text } from "@chakra-ui/react";
import { useEthers, useEtherBalance } from "@usedapp/core";
import { formatEther } from "@ethersproject/units";
import Identicon from "../Identicon";
type Props = {
handleOpenModal: any;
};
export default function ConnectButton({ handleOpenModal }: Props) {
const { activateBrowserWallet, account } = useEthers();
const etherBalance = useEtherBalance(account);
function handleConnectWallet() {
activateBrowserWallet();
}
return account ? (
<Box
display="flex"
alignItems="center"
background="gray.700"
borderRadius="xl"
py="0"
>
<Box px="3">
<Text color="white" fontSize="md">
{etherBalance && parseFloat(formatEther(etherBalance)).toFixed(3)} ETH
</Text>
</Box>
<Button
onClick={handleOpenModal}
bg="gray.800"
border="1px solid transparent"
_hover={{
border: "1px",
borderStyle: "solid",
borderColor: "blue.400",
backgroundColor: "gray.700",
}}
borderRadius="xl"
m="1px"
px={3}
height="38px"
>
<Text color="white" fontSize="md" fontWeight="medium" mr="2">
{account &&
`${account.slice(0, 6)}...${account.slice(
account.length - 4,
account.length
)}`}
</Text>
<Identicon />
</Button>
</Box>
) : (
<Button
onClick={handleConnectWallet}
bg="blue.800"
color="blue.300"
fontSize="lg"
fontWeight="medium"
borderRadius="xl"
border="1px solid transparent"
_hover={{
borderColor: "blue.700",
color: "blue.400",
}}
_active={{
backgroundColor: "blue.800",
borderColor: "blue.700",
}}
>
连接钱包
</Button>
);
}
```
转移比特币 index.tsx
```typescript=
import { Box, Button, Center, Flex, FormControl, Input, InputGroup, NumberInput, NumberInputField, useMediaQuery, useToast } from "@chakra-ui/react";
import { useEtherBalance, useEthers, useSendTransaction } from "@usedapp/core";
import { utils } from "ethers";
import { useEffect, useState } from "react";
import { formatEther } from "@ethersproject/units";
const STATUS_CONFIG: any = {
"Success": 'success',
"Exception": 'error',
};
const TransferringEthers: React.FC = () => {
const [amount, setAmount] = useState<number>(0);
const [receipent, setReceipent] = useState<string>('');
const [disabledButton, setDisabledButton] = useState<boolean>(true);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isTablet] = useMediaQuery("(min-width: 750px)");
const [isMobile] = useMediaQuery("(min-width: 320px)");
const { sendTransaction, state } = useSendTransaction();
const { account } = useEthers();
const etherBalance = useEtherBalance(account);
const toast = useToast();
const [buttonText,setButtonText] = useState<string>('转移');
const handleAmountInputChange = (e: any) => {
setAmount(e?.target?.value);
}
const handlesetReceipentInputChange = (e: any) => {
setReceipent(e?.target?.value);
}
const handleTransfer = () => {
setIsLoading(true);
sendTransaction({ to: receipent, value: utils.parseEther(amount.toString()) });
}
useEffect(() => {
if (amount > 0 && receipent) {
setDisabledButton(false);
}
}, [amount, receipent])
const toastMessage = (values: any) => {
toast({
title: `${values?.errorMessage}`,
status: STATUS_CONFIG[values?.status],
isClosable: true,
position: "top",
})
}
useEffect(() => {
if (state?.status === "Exception" || state?.status === "Success" || state?.status === "Fail") {
setIsLoading(false);
toastMessage(state);
}
}, [state, toastMessage])
useEffect(() => {
if (etherBalance && amount) {
const count = formatEther(etherBalance);
if(Number(amount) > Number(count)) {
setButtonText('余额不足');
setDisabledButton(true);
} else {
setButtonText('转移');
setDisabledButton(false);
}
}
}, [amount, etherBalance]);
return (
<>
<Flex
margin="auto"
paddingTop={isMobile ? "10vh" : isTablet ? "12vh" : "15vh"}
width="100%"
minWidth="500px"
>
<FormControl isRequired>
<Box
w="450px"
borderRadius="35px"
m="auto"
backgroundColor="withAlpha(gray.900, 0.9)"
boxShadow="2xl"
p="25px"
>
<Box
id="Receipent Field"
p="5"
height="80px"
backgroundColor="gray.100"
borderRadius="25"
>
<Flex>
<InputGroup>
<Input
id="receipent"
p="0"
border="0"
placeholder="账户"
w="100%"
focusBorderColor="none"
onChange={handlesetReceipentInputChange}
disabled={isLoading}
/>
</InputGroup>
</Flex>
</Box>
<Flex height="2"></Flex>
<Box
id="Amount Field"
p="5"
height="80px"
backgroundColor="gray.100"
borderRadius="25"
>
<Flex>
<InputGroup>
<NumberInput w="100%" focusBorderColor="none">
<NumberInputField
id="amount"
p="0"
placeholder="0.0"
border="0"
onChange={handleAmountInputChange}
disabled={isLoading}
/>
</NumberInput>
</InputGroup>
</Flex>
</Box>
<Flex height="2"></Flex>
<Center>
<Button
id="Transfer Button"
border="0"
w="100%"
h="60px"
borderRadius="25"
onClick={handleTransfer}
isDisabled={disabledButton}
isLoading={isLoading}
loadingText='正在转移中...'
colorScheme='pink'
>
{buttonText}
</Button>
</Center>
</Box>
</FormControl>
</Flex>
</>
);
}
export default TransferringEthers;
```