Skip to main content

7-17

1 自己跟以前相比,有哪些进步?

  • 前端基础方面:react组件封装、ts熟练度,对前端也有一个系统的认识
  • 做事、沟通方面:抓得住重点
  • 区块链方面:熟练联调合约、常见swap协议、稳定币协议是知道的
  • 学习方面:总结出自己的一套学习方法
  • 解决问题方面:善于利用Google检索问题、解决问题、并记录

-- 2022-07-19 12:18:08

2 Nextjs如何部署

部署方式很多,大致有:vercel、node、docker等,详见 Deployment

Docker部署

官方示例:with-docker

官方示例(多环境):with-docker-multi-env

坑1:安装git

RUN apk add --no-cache git

[1] https://github.com/sleede/fab-manager/issues/299

坑2:删除不需要的安装脚本

yarn 示例:

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

坑3:修改 yml 文件

示例,主要注意 服务名镜像名

version: '3'

services:
crv-ftx-web-stage:
build:
context: ../../
dockerfile: docker/staging/Dockerfile
image: coinflow/crv-ftx-web:stage
ports:
- '3000:3000'

示例

TODO

3 Nextjs接口代理

作用

解决浏览器跨域问题

配置

// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
]
},
};

请求

请求到本机,就会被代理到 destination

http://localhost:3000/api

[1][NextJs CORS issue](https://stackoverflow.com/questions/65058598/nextjs-cors-issue)

4 Multicall原理

实现

实现multicall有两种方法:1.合约转发实现 2.provider.call

合约转发

以下是uniswap根据 multicall2 更改的multicall

// SPDX-License-Identifier: MIT
pragma solidity =0.7.6;
pragma abicoder v2;

/// @notice A fork of Multicall2 specifically tailored for the Uniswap Interface
contract UniswapInterfaceMulticall {
struct Call {
address target;
uint256 gasLimit;
bytes callData;
}

struct Result {
bool success;
uint256 gasUsed;
bytes returnData;
}

function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
timestamp = block.timestamp;
}

function getEthBalance(address addr) public view returns (uint256 balance) {
balance = addr.balance;
}

function multicall(Call[] memory calls) public returns (uint256 blockNumber, Result[] memory returnData) {
blockNumber = block.number;
returnData = new Result[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
(address target, uint256 gasLimit, bytes memory callData) =
(calls[i].target, calls[i].gasLimit, calls[i].callData);
uint256 gasLeftBefore = gasleft();
(bool success, bytes memory ret) = target.call{gas: gasLimit}(callData);
uint256 gasUsed = gasLeftBefore - gasleft();
returnData[i] = Result(success, gasUsed, ret);
}
}
}

无部署multicall

无部署multicall主要通过provider.call实现,具体原理请参见:Deployless Multicall for historical EVM data

通过 ethcall 对于无部署multicall的实现来看,她通过provider.call来实现

image-20220721131400717

[1][ethcall](https://github.com/Destiner/ethcall)

[2][multicall2](https://github.com/makerdao/multicall)

5 拷贝文件到服务器

rsync -av --delete /Users/jiangjin/Documents/03_ftx/fox-ftx-interface [email protected]:/www

6 利用tree生成目录结构

# 显示深度为3级
tree -L 3

# 只显示目录,不显示文件
tree -d -L 3

[1][github中,生成项目展示的目录结构](https://juejin.cn/post/6844903843562520589)

7 Mui输入框隐藏label

关键:InputLabelProps={{shrink: false}} and label=''

<TextField
id="outlined-select-gender"
select
label={gender=== "" ? "Gender": ""}
className={classes.textField}
value={gender}
onChange={handleChange}
InputLabelProps={{shrink: false}}
SelectProps={{
MenuProps: {
className: classes.menu,
},
}}
margin="normal"
variant="outlined"
>
{genders.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>

[1][Remove Label on Material-UI Select Text Field](https://stackoverflow.com/questions/56879153/remove-label-on-material-ui-select-text-field)

8 PR时触发的GithubAction脚本示例

运行lint

# /.github/workflows/test.yml

name: Run tests

on: [pull_request]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: restore yarn
uses: actions/cache@v2
with:
path: |
node_modules
*/*/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
- name: install
run: yarn
- name: lint
run: yarn lint

9 Eslint-Cannot read property 'loc' of undefined

原因

在使用 eslint-plugin-unused-imports 插件时,枚举类型导致出错,具体原因未知

解决

用对象模拟枚举

const LOCALES = {
'zh-CN': 'zh-CN',
'zh-TW': 'zh-TW',
}

type LOCALE = keyof typeof LOCALES

export type LanguageLabels = {
[key in LOCALE | string]: string
}

10 System UI Theme Specification(SystemUI主题规范)

[1][System UI Theme Specification](https://github.com/system-ui/theme-specification)

image-20220723150349579

11 React18变更

一共4部分:

  • Concurrent Model:并发渲染模型;
  • Automatic Batching:多个state合并为一个更新;
  • Transitions:指定渲染优先级;
  • Suspense:更方便的组织请求和loading状态;

Transitions

import {startTransition} from 'react';

const handleChange = useCallback(()=> {
// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
// Transition: Show the results
setSearchQuery(input);
});
}, [])

解释:第一时间响应用户输入,再展示输入结果

Suspense

完整设计文章见 0213-suspense-in-react-18

<Suspense fallback={<PageGlimmer />}>
<RightColumn>
<ProfileHeader />
</RightColumn>
<LeftColumn>
<Suspense fallback={<LeftColumnGlimmer />}>
<Comments />
<Photos />
</Suspense>
</LeftColumn>
</Suspense>

从概念上讲,您可以将Suspense其视为类似于catch块。但是,它不是捕获错误,而是捕获“挂起”的组件。树中的任何组件都可以“挂起”,这意味着它还没有准备好渲染。(原因是任意的,但通常可能是由于缺少代码、数据等)

特殊情况
<div>
{showComments && (
<Suspense fallback={<Spinner />}>
<Panel>
<Comments />
</Panel>
</Suspense>
)}
</div>

提交的树总是一致的:假设showCommentsfalse变为true。即使Panel准备好,但Comments未准备好,那也触发Spinner

12 如何通过 NPM 在应用程序之间共享 React 组件

[1][如何通过 NPM 在应用程序之间共享 React 组件](https://nosleepjavascript.com/package-react-components/)

13 Ts中extends和infer

TODO

Extends

作用:

  • 表示继承/拓展的含义
  • 表示约束的含义
  • 表示分配的含义

约束

// 约束必须包含Contract,且缺省值为Contract
function getContract<T extends Contract = Contract>(){}

分配

// Exclude定义(排除)
type Exclude<T, U> = T extends U ? never : T

// Extract定义(包含)
type Extract<T, U> = T extends U ? T : never

// Pick定义(选取)
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}

// Partial定义(全可选)
type Partial<T> = {
[K in keyof T]?: T[K]
}

[1][Typescript中的extends关键字](https://cloud.tencent.com/developer/article/1884330)

[2][白话typescript中的【extends】和【infer】](https://juejin.cn/post/6844904146877808653)

14 React的Suspense如何使用

如果在nextjs中使用,要注意服务器端渲染,要关闭ssr

关闭方法见 15

15 Nextjs预渲染每一个页面

所以,如果要进行客户端渲染,有两种方式:

#1 将数据放入useEffect中请求
export default function Home() {
const [data, setData] = useState();

useEffect(() => {
queryData().then((data: any)=> {
setData(data);
})
}, []);

return (
<div className={styles.container}>
{JSON.stringify(data)}
</div>
);
}
#2 动态导入,关闭ssr
const Home = dynamic(
() => import('../components/Home'),
{ ssr: false }
)

[1][Warning: Text content did not match. Server: "I'm out" Client: "I'm in" div](https://stackoverflow.com/questions/66374123/warning-text-content-did-not-match-server-im-out-client-im-in-div)

16 一个monorepo中存在多个react版本

该实现 较为困难,但反过来想,在什么场景下需要多个react版本?

17 fabric.js

FabricJS.com is a simple and powerful Javascript HTML5 canvas library. It is also an SVG-to-canvas parser.

[1][fabric.js](https://github.com/fabricjs/fabric.js)