9-6
1 总结设计模式
TODO
2 利用Excel快速批量插入数据到mysql数据库
[2] 快速导入100万条Excel数据到MySql.https://blog.csdn.net/CSDN1887/article/details/83862035
3 useScrollPosition()
A React hook for updating components when the scroll position of the window on the y-axis changes.
4 remix在线编译器无法下载(or下载慢)怎么办?
用本地搭建一个remix
step1:
yarn global add remix-ide
并将yarn的目录放入环境变量
export PATH="/User/jiangjin/.yarn/bin:$PATH"
step2:
remix-ide
提示找不到remixd,删除与remixd相关代码
vim /Users/jiangjin/.config/yarn/global/node_modules/remix-ide/bin/remix-ide
# 删除以下内容
var remixd = require('remixd')
var router = new remixd.Router(65520, remixd.services.sharedFolder, { remixIdeUrl: 'http://localhost:8080' }, (webSocket) => {
remixd.services.sharedFolder.setWebSocket(webSocket)
remixd.services.sharedFolder.setupNotifications(folder)
remixd.services.sharedFolder.sharedFolder(folder, false)
})
router.start()
step3:
下载solc包,下载地址:https://github.com/ethereum/solc-bin/tree/gh-pages/bin
放入/Users/jiangjin/.config/yarn/global/node_modules/remix-ide/assets/solc-bin/bin目录下(请新建)
并更改 /Users/jiangjin/.config/yarn/global/node_modules/remix-ide/assets/js/0.7.7/app.js文件,改动如下:
//baseurl: 'https://solc-bin.ethereum.org/bin'
baseurl: 'http://localhost:8080/assets/solc-bin/bin'
//var url = 'https://ethereum.github.io/solc-bin/bin/soljson-' + versionString + '.js'
var url = 'http://localhost:8080/assets/solc-bin/bin/soljson-' + versionString + '.js'
step4:
remix-ide
# 重启ide
附:我自己下载了0.5.4, 0.5.16, 0.7.2, 0.7.5这四个版本,需要的可以下载
这是整个assets目录包,下载地址:https://nahaohao.lanzoui.com/iSdMatpiyri
参考
[1] solc-bin编译器下载.https://github.com/ethereum/solc-bin/tree/gh-pages/bin
[2] Remix本地环境搭建.https://blog.csdn.net/qq_32501663/article/details/110876930
5 如何去掉input type=number时输入框内的上下箭头
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type="number"]{
-moz-appearance: textfield;
}
6 如何适配iphoneX-ios
两步
Step 1
html头部加入 viewport-fit=cover
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
Step 2
.fixed-bottom{
bottom: calc(67px + constant(safe-area-inset-bottom));
bottom: calc(67px + env(safe-area-inset-bottom));
/* 如果不支持env或者constant不受影响 */
}
说明:兼容不同IOS版本写法
padding-bottom: constant(safe-area-inset-bottom);
/* 兼容 IOS < 11.2 */
padding-bottom: env(safe-area-inset-bottom);
/* 兼容 IOS >= 11.2 */
7 react-swiper结合
Swiper React Components.https://swiperjs.com/react#swiper-props
首先,官网出了swiper7,就只有swiper7的文档了,我死活没找到以前的文档,
swiper6+react的文档
:https://github.com/nolimits4web/swiper-website/blob/v6/src/pages/react.mdx
api文档
:https://www.swiper.com.cn/api/autoplay/19.html
因为ES module的问题,我用不了swiper7,
大概使用步骤,
Step1: 安装
yarn add swiper@^6 # 指定安装6的版本
Step2: 引入文件
// swiper bundle stylesimport 'swiper/swiper-bundle.min.css'// swiper core stylesimport 'swiper/swiper.min.css'// modules stylesimport 'swiper/components/navigation/navigation.min.css'
import 'swiper/components/pagination/pagination.min.css'...
Step3: 拿到swiper对象
const swiperRef = useRef<SwiperClass | undefined>(undefined)
// 拿到实例化的swiper就可以直接调用其API了
<Swiper
spaceBetween={50}
slidesPerView={1}
onSlideChange={(e: SwiperClass) => {
// console.log('slide change', e, e.activeIndex)
setCurrentTabIndex(e.activeIndex)
}}
onSwiper={(e) => {
console.log('[e](onSwiper):', e)
swiperRef.current = e // 这里可以拿到实例化后的swiper
}}
>
<SwiperSlide></SwiperSlide>
</Swiper>
8 CJS和ESM等模块概述
⚠️ 目前有诸如webpack、vite等打包工具,其支持各种模块导入、导出写法,所以不必担心有这么多模块,这么多模块写法,是历史发展问题,了解即可。
有以下模块规范:CJS、AMD、CMD、UMD、ESM等规范,下面从特点、环境、应用、语法、示例五个方面来对比
CJS
特点:
- 同步阻塞加载
- 缓存加载
环境:服务器环境
应用:nodeJs实现了CJS规范
语法:
导入:require('路径')
导出:module.exports和exports
说明:exports是module.exports的一个引用,即const exports = module.exports
示例
// a.js
module.exports = {
a: 'hello world'
}
// b.js
var moduleA = require('./a.js');
console.log(moduleA.a); // 打印出hello world
AMD
特点:异步加载
环境:浏览器
应用:requireJs实现AMD规范
语法:
导入:require(['模块名称'], function ('模块变量引用'){// 代码});
导出:define(function (){return '值');
示例:
// a.js
define(function (){
return {
a:'hello world'
}
});
// b.js
require(['./a.js'], function (moduleA){
console.log(moduleA.a); // 打印出:hello world
});
CMD
特点:CMD与AMD类似,是基于AMD改进的一种规范,对依赖模块的执行时机不同,CMD就近依赖,AMD前置依赖
环境:浏览器
应用:seaJs实现CMD规范
语法:
导入:define(function(require, exports, module) {});
导出:define(function(require, exports, module) {});
说明:相对于AMD,CMD中多出了几个钩子参数 require, exports, module
示例:
// a.js
define(function (require, exports, module){
exports.a = 'hello world';
});
// b.js
define(function (require, exports, module){
var moduleA = require('./a.js');
console.log(moduleA.a); // 打印出:hello world
});
UMD
特点:是一个CJS、AMD和浏览器环境的融合怪,没有具体出名的实现应用,可以看一下常规实现方法:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
//AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
//Node, CommonJS之类的
module.exports = factory(require('jquery'));
} else {
//浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
//方法
function myFunc(){};
//暴露公共方法
return myFunc;
}));
ESM
特点:ESM是ES2015(ES6)推出的模块规范,支持同步和按需加载
环境:浏览器
语法:
导入:import {模块名A,模块名B...} from '模块路径'
导出:export和export default
异步导入:import('模块路径').then()方法
示例:
// a.js
export default const a = 123
export const b = 456
// b.js
import a, { b } from 'a.js'
// 异步导入
Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
])
.then(([module1, module2, module3]) => {
···
});
总结
CJS、AMD、CMD、UMD、ESM它们是一步一步发展而来的,都是前一个规范无法满足开发者多种需求而被创造出来的。目前流行的是ESM规范。
(完)
[1] JS模块规范:AMD、UMD、CMD、commonJS、ES6 module.https://segmentfault.com/a/1190000012419990
9 注意123..toFixed()将丢弃小数部分,与bignumber.js的 tofixed
行为不一样
123.456..toFixed()
=> '123'
而bignumber.js中如下:
const bignumber = new Bignumber(123.456)
bignumber.toFixed()
// 将bignumber转为字符串,不会成为科学计数法bignumber.toString() // 转为字符串,超过7位则称为科学计数法(123.111).toFixed() // 转为字符串,丢弃小数部分
=> '123.456'
联想:如何将数字进行科学计数法?
num.toExponential()
//"1.23456e+5" 转化为科学计数法Number("1.23456e+5") //123456
//Exponential 指数
10 useOnClickOutside-点击外部,回调handler
一般手机端使用(弹出层打开之后,点击其他区域关闭弹出层)
/*
* @Author: jiangjin
* @Date: 2021-09-07 16:15:28
* @LastEditTime: 2021-09-07 16:18:29
* @LastEditors: jiangjin
* @Description:
* 点击外部,回调handler
*/
/**
* @param node
* @param handler 回调函数,一般进行模态框关闭
*/
import { RefObject, useEffect, useRef } from "react"
export function useOnClickOutside<T extends HTMLElement>(
node: RefObject<T | undefined>,
handler: undefined | (() => void)
) {
const handlerRef = useRef<undefined | (() => void)>(handler)
useEffect(() => {
handlerRef.current = handler
}, [handler])
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (node.current?.contains(e.target as Node) ?? false) {
return
}
if (handlerRef.current) handlerRef.current()
}
document.addEventListener("mousedown", handleClickOutside)
return () => {
document.removeEventListener("mousedown", handleClickOutside)
}
}, [node])
}
联想:如果handler变化了,useRef会重新赋值吗?
经过上次测试,useState无论初始值是否变化,都只会执行一次
TODO
11 如何使用 docusaurus
文档框架?
Docusaurus是facebook开源的一个用于搭建文档项目,与gitbook等雷同
如何修改网站信息?
如何修改样式?
请看文档:https://docusaurus.io/zh-CN/docs/next
12 useEffect的 return
什么时候执行?
const [state, setState] = useState(1)
useEffect(() => {
return () => {
console.log("[APP卸载了]:")
}
}, [state])
return (
<>
{" "}
<button
onClick={() => {
setState((prev) => prev + 1)
}}
>
刷新
</button>{" "}
</>
)
以下情况会刷新:
- 组件销毁
- useEffect依赖的数据变化的时候也会更新
13 项目引入了redux,如何开启redux-tools插件呢?
详见地址:https://github.com/zalmoxisus/redux-devtools-extension#installation
分两种情况:
第一种,如果没有引入中间件
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore( reducer, /* preloadedState, */ composeEnhancers);
第二种,如果引入了中间件,则这样使用:
import { createStore, applyMiddleware, compose } from "redux"
const composeEnhancers =
(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
reducer,
/* preloadedState, */ composeEnhancers(applyMiddleware(...middleware))
)
14 data signature does not match function rewardInfo.
函数调用错误,
try {
// 注意:解码的时候是decodeFunctionResult,而非decodeFunctionData
// 而编码的时候是encodeFunctionData
result = contractInterface.decodeFunctionResult(fragment, data)
} catch (err) {
console.debug("[解析合约参数失败](toPackageState)")
return { valid: true, loading: false, error: true, syncing, result }
}
interface中有四个方法比较雷同:
方法名 | |
---|---|
encodeFunctionData | |
encodeFunctionResult | |
decodeFunctionData | |
decodeFunctionResult |
一般用 encodeFunctionData-decodeFunctionResult
的组合
如果用decodeFunctionData则会验证头部函数信息,而目前multicall合约返回值并没有头部函数信息。
15 注意...扩展运算符是浅拷贝
// state.callResults如下结构:{ [97]:{ "0x01Af8d162E217eE0eF22f7ddb52488870335ca12-0xcbecf6b5000000000000000000000000bf992941f09310b53a9f3436b0f40b25bccc2c33": { "data": "0x00000000000000000000000000000000000000000000000000002658f2d67c27", "blockNumber": 12298223 } }}const isTrue = callResultsUpdate == state.callResultsconst isTrue1 = callResultsUpdate?.[97] == state.callResults?.[97]console.debug('[isTrue]:', isTrue, isTrue1)=> false true
16 shallowEqual的true为不更新,false为更新
17 Line 0: Parsing error: Cannot read property 'map' of undefined
此问题发生原因为 react-scripts
版本和 typescript
版本不匹配而导致的,项目中
react-scripts版本为3,而typescrip为4
解决方法:统一版本即可
# 注意安装最新版react-scripts的第四版,否则还会出现问题yarn add react-scripts@^4yarn add -D typescript@^4.4
检查 pakeage.json
的版本
"react-scripts": "^4","typescript": "^4.4"
联想:^ ~的含义?
一句话:
~1.15.2 := >=1.15.2 <1.16.0
^3.3.4 := >=3.3.4 <4.0.0
附:MAJOR,MINOR,PATCH的含义
1.15.2对应就是MAJOR,MINOR.PATCH:1是marjor version;15是minor version;2是patch version。
MAJOR:这个版本号变化了表示有了一个不可以和上个版本兼容的大更改。
MINOR:这个版本号变化了表示有了增加了新的功能,并且可以向后兼容。
PATCH:这个版本号变化了表示修复了bug,并且可以向后兼容。
https://blog.csdn.net/njweiyukun/article/details/70309066
18 保留有效小数-向上取整-Decimal-Bignumber
import Decimal from "decimal.js"
// 设置Decimal精度和取整方式
Decimal.set({ precision: DECIMAL_PRECISION, rounding: DECIMAL_ROUNDING,})
// TODO 设置其有效位数为5位,向上取整
const bigLeftRangeValue = new Decimal('0.000111116').toSignificantDigits(5)
bigLeftRangeValue.toFixed()
=> 0.00011112
[1] decimal.js文档.https://mikemcl.github.io/decimal.js/#modes
19 迁移git项目
# 查看git remote -v
git remote set-url origin https://github.com/USERNAME/REPOSITORY.git# 查看是否生效git remote -v
之后把远端main分支改名,后将本地main分支推送上去,再删除远端改名的main分支即可(建议先备份分支,再操作)
联想:git删除远端分支
git push origin :main# 表示将空分支推送给远端main
联想:如何新增远端仓库呢?
git remote add origin https://github.com/octocat/Spoon-Knife.git
20 ts忽略文件检测
- 单行忽略(添加到特定行的行前来忽略这一行的错误)
- 跳过对某些文件的检查 (添加到该文件的首行才起作用)
// @ts-ignore
// @ts-nocheck
21 useEffect依赖变化的问题-只有组件刷新才会走useEffect吗?
答案是否定的,即使页面没有引用变化的数据,数据变化了,也会走useEffect,就拿Updater组件来说:
export default function Updater(){
const latestBlockNumber = useBlockNumber()
useEffect(() => {
debugger
}, [latestBlockNumber])
return null
}
即使页面什么都不渲染,但只要 latestBlockNumber
变化,都会走useEffect
22 git打标签-git tag
git tag -a v1.0
回车之后进入vim书写注释
删除本地
git tag -d v1.0
删除远端
git push origin :v1.0
推送tag
git push origin v1.0
23 As与Ts
https://www.assemblyscript.org/quick-start.html
24 引入的组件会执行return之前的内容,即使没有渲染
25 jest测试中的it中变量是有范围的
两个it之间是状态隔离的
it('add listeners', () => {
store.dispatch(
addMulticallListenerAction({
chainId: 97,
calls: [call1],
})
)
expect(store.getState().callLiteners[97]).toEqual({
[`${DAI_ADDRESS}-0x`]: { ['1']: 1 },
})
})
it('remove listeners', () => {
store.dispatch(
addMulticallListenerAction({
chainId: 97,
calls: [call1],
})
)
store.dispatch(
removeMulticallListenersAction({
chainId: 97,
calls: [call1],
})
)
expect(store.getState().callLiteners[97]).toEqual({ [`${DAI_ADDRESS}-0x`]: {} })
})
26 要实现鼠标点击效果
:hover,
:focus {
background-color: ${({ pending, theme }) => (pending ? darken(0.05, theme.primary1) : lighten(0.05, theme.black))};
border: 1px solid ${({ theme }) => darken(0.1, theme.primary1)};
box-shadow: unset;
}
:active {
border: 1px solid ${({ theme }) => darken(0.6, theme.white)};
}
思想:给active的border加深多一些即可
27 在组件传参的时候不要传递key属性,应该用其他名称(key为关键字),否则为undefined
<>
{popupList.map((item) => {
return <PopupItem {...item} popKey={item.key} key={item.key} />
})}
</>
28 一个组件需要调用另一个组件的子组件的方法,通过ref的方式最为方便
联想:既是受控组件又是非受控组件,则外部通过ref来改变状态
思想:要想改变非受控组件的状态(内部维护的状态),则通过ref引用其暴露的函数去改变状态
useEffect(() => {
if (!setIndexRef) return
setIndexRef.current = (index: number | undefined | null) => setcurrIndex(index)
}, [setIndexRef])
当然也可以通过传递函数的方式,再外部组件使用ref引用
29 受控组件和非受控组件
一般都使用受控组件,但复杂的组件中两个是一起用的,有一些受控组件的经验:
组件传参方式尽量采用单个变量,而非整个对象
如果不是业务组件,内部不要写太多逻辑,只渲染数据即可
需要什么数据,就传入什么数据
联想:受控组件和非受控组件组合的最佳实践?