共计 4845 个字符,预计需要花费 13 分钟才能阅读完成。
第七期: 前端九条启发分享
一、ts 数组类型推导莫名被烦扰
事件是这样的, 周五的时候须要做一个小优化, 某个文件外面本来导出 3 个 “json 对象
“, 我须要改成导出三个function
不便依据传参扭转导出内容, 这时就产生了奇怪的类型报错, 假如以后有如下的代码:
上面代码不会报错, 能够失常运行
export interface Dog {
name: string;
age?: 1 | 2 | 3;
}
export const a = (): Dog => ({name: "金毛",});
export const b = () => ({
name: "比熊",
age: 2,
});
export const c = () => ({name: "拉布拉多",});
const cc: Dog[] = [a(), b(), c()];
然而奇怪的是, 上面这段代码就会报错
export interface Dog {
name: string;
age?: 1 | 2 | 3;
}
export const a = (): Dog => ({name: "金毛",});
export const b = () => ({
name: "比熊",
age: 2,
});
export const c = (): Dog => ({name: "拉布拉多",});
const cc: Dog[] = [a(), b(), c()];
我只是为第三个办法指定了返回值, 第二个办法竟然报错了, 我不为第三个办法指定返回值反而第三个办法不会报错, 接下来还有奇怪的景象, 但我为第三个办法指定为返回 any 类型的时候, 竟然第二个办法也不报错了:
通过钻研发现, 当数组内某个值被指定为 any
的时候, 数组类型会变成 any[]
, 所以才有了c()
被指定为返回 any 不报错。
当 a 与 c
两个办法都被指定为 Dog
类型时, ts
发现 b 办法
的返回值并不一定合乎 Dog
的推演, 因为 Dog
类型外面的 age
只能含有 1|2|3
所以报错, 然而如果你齐全不给 a b c
指定返回值类型也不会报错, ts 会主动推导出 2 在范畴内, 真神奇!
二、如何设计 undefined | bl 这种构造的组件
举个例子假如 tip 提示框
组件, 他有一个是否显示的参数 showTip
为布尔值, 当这个值为 true
的时候就算用户没有用鼠标悬停这个弹框也会呈现, 为 false
就是怎么也无奈让它显示。
以后有一个需要要求进入页面后这个框被动弹出停留 3s
后隐没, 那其实咱们很容易就想到将 showTip
赋予为 true
3 秒而后变为undefined
即可, 因为只存在两种状况, 要么 true 要么 undefined, 就好比如下的代码编写形式:
const obj = {};
if(isFirstOpenPage){obj.showTip = true;}
return <tip {...obj}>
然而当我应用某个组件库的时候呈现了只有定义过 showTip
属性就无奈置为 undefined
的状况, 导致我弹出 tip
之后就无奈复原到让用户去管制显隐了。
这其实就是代码设计时候要思考的问题了, 当咱们设计一个值为 布尔
的属性时, 应该同时也思考到 undefined
也可能是一种传值状况。
三、react 如何刷新组件本身
我遇到的状况是, 有 a, b, c
三个组件, 这三个组件别离对应三种不同的非凡状况, 每个状况都有可能呈现, 但这三个组件同一时间只能呈现一个, 比方以后呈现了 a
组件, 用户点击了敞开才会呈现 b
组件, 这就导致每次当用户点击敞开时我要判断是否另外两个组件须要被渲染进去。
问题点就在于比方移除 a 组件
, 组件库的做法是间接把 a 的 dom 构造
移除了, 导致 react 监控不到。
const [_, forceUpdate] = useReducer(x => x + 1, 0);
if (showA) {return <A forceUpdate={forceUpdate} />;
} else if (showB) {return <B forceUpdate={forceUpdate} />;
} else if (showC) {return <C forceUpdate={forceUpdate} />;
} else {return null;}
每个组件外面
onClose={() => {if (forceUpdate) {forceUpdate();
}
}}
上述办法的要害就是 useReducer
的变动能够引起组件的从新渲染。
四、为字符串插入 jsx 元素
事件是这样的, 比方以后咱们有个 i18n 文案
是highest price {max} - lowest price {min}
, 现有办法能够通过传入两个字符串替换掉 {max}
与{min}
, 然而只能用字符串替换, 无奈插入 dom 构造, 比方我想用蓝色的字来替换。
假如 intl
办法能够把字符串外面的 {max} 替换掉, 咱们对 intl
进行裁减变成intlPlus
, 上面是平时应用的形式。
intl.format("highest price {max} - lowest price {min}"
["99", "33"]
)
intlPlus 的编写
import intl from './intl';
const pix = '-------------';
export default function intlPlus(i18n: string, arg: any[]) {
const len = arg.length;
const box = Array(len).fill(pix);
const text = intl.format(i18n, box);
const textArr = text.split(pix);
const res: any[] = [];
for (let i = 0; i < textArr.length; i++) {res.push(textArr[i]);
if (arg[i] !== undefined) {res.push(arg[i]);
}
}
return res;
}
下面的原理就是应用 '-------------';
作为站位符号, 而后再按程序对占位符号进行切割, 而后按一个文案一个插值的模式循环插入, 并以数组的模式输入进来, 应用办法如下:
intl.format("highest price {max} - lowest price {min}"
["99", <span style={{color: red}}> 33 </span>
]
)
五、如何避免测试环境地址泄露
比方咱们平时 测试环境
的地址不要让外界看到, 比方如下的代码就是会泄露测试域名的代码:
const pathObj = {
prod: 'www.xxxxxx.com',
dev: 'www.xxxxxxx-dev.com',
test: 'www.xxxxxx-test.com'
}
// ....
if(location.host === 'localhost:3000'){window.open(pathObj.dev)
}
插件 webpack.DefinePlugin
闪亮退场✨, 这个插件能够让咱们设置一些 "全局"
(带引号的) 的变量, 这些变量能够在正式 打包之前
应用:
plugins: [
new webpack.DefinePlugin({
isDev:
process.env.NODE_ENV === "production"
? JSON.stringify("false")
: JSON.stringify("true")
}),
]
下面很奇怪的应用了 JSON.stringify
, 因为只有这样webpack
能力把它当做字符串来解决, 否则会被当做语句来解决, 接下来咱们举个应用时的例子:
咱们察看打包文件:
察看可知 ’oooooooo’ 曾经不存在于打包文件外面了。
它的原理就是在全局进行替换, 比方下面的代码:
// 打包前:
if (isDev) {console.log("tttttttttt");
} else {console.log("ooooooooooo");
}
// 打包时:
if (false) {console.log("tttttttttt");
} else {console.log("ooooooooooo");
}
很显著了, tree-shaking
不会放过这种代码, 所以上面的 ’ooooooo’ 逻辑就会被删掉。
这个插件有点难了解的点就是, 它并不是运行时执行的, 而是 tree-shaking
前进行了一次全局的替换。
之所以它能够间接写在全局 isDev
, 然而不能够写window.isDev
就是因为它并没有挂载在 widnow 对象上, 这类变量并不会在用户端运行。
六、写成 {} 导出后 i18n 翻译不实时失效
有很多须要实时变动的配置最好不要设计为 json 的模式, 比方我的项目里的翻译, 当用户切换语言英语为中文的时候, 发现某些中央翻译没有变动仍然还是英语, 这些中央的特色就是全是导出的 json 相似上面这种:
export UserName = {title: <span> {i18n(USER_NAME_TITLE)} </span>
}
应用形式
import {UserName} from './userName'
// ...
<Table
columns={[UserName]}
>
上述写法的 表格表头
并不会随着语言的切换而扭转文案。
七、item2 的宰割很好用
命令行工具能够很大的缓解咱们多我的项目启动的问题, 如果你是在 vscode
提供的 shell
上启动多个我的项目, 就会感觉到来回切换有点吃力了, 更糟的状况是你同时开发两个以上 微前端
我的项目, 所以这个 item2
必须好好安利一下, 因为这个切实是太好用了, 还没这样玩的敌人能够快快玩起来:
每次点击都会减少一个小窗口, 让咱们看看把控制台分成 ’6 份 ’:
为了避免凌乱, 咱们能够为每个窗口命名:
设置过程如下:
还能够设置本人喜爱的背景图案:
设置过程如下:
八、tip 提醒离奇被暗藏
我在做的一个弹出框外面有个 table 表格
, 这个table
其中一列的表头默认是弹出状态, 然而遇到的 bug 是这个弹出状态某些时候会一闪而过, 从新变回未弹出的状态, 看过组件库的源码之后确定不是组件自身的问题。
通过屡次测试发现, 这个 bug 与点击弹出弹框的按钮的地位无关, 这才让我想明确 bug 的起因, 因为这个弹出框有一个弹出动画, 从右边由小变大的呈现, 这个变大的过程中理论曾经预渲染了这个弹框外面的组件, 导致弹框呈现的过程中会通过鼠标, 这就导致组件认为用户悬停过, 导致 tip 暗藏 …
解决形式是将这个弹框呈现时的 300 毫秒的鼠标事件禁止掉。
九、借助 Whistle 设置线上域名开发本地代码, 避免被 csrf 进攻
因为 server
端常常会加一些安全策略, 比方只能某个 referer
的网站能力调用 api
, 其余网址过去的都会报403
, 这个时候咱们前端可怜的http://localhost:3000
就遭殃了, 每次都要与相干人员沟通本地调试的问题。
索性咱们间接应用测试环境的域名进行开发就得了, 不应用 http://localhost:
(相似于 windows 批改本地的 host 文件) 总算行了吧 …
第一步: 装置 Whistle
npm install -g whistle
w2 start -p 8899 // 启动服务
间接关上域名即可看到操作界面: http://localhost:8899
第二步: 装置 proxy
因为咱们须要把浏览器的申请全副代理到 Whistle, 所以须要用到 proxy 这个谷歌插件,
搜寻 : Proxy SwitchyOmega
这一步是代理浏览器的申请到这个地址
第三步: 配置 Whistle
后面的是被代理的地址, 空格前面是指标地址
以后有这样一个页面
代理之后
第六步: Whistle 配置秘钥证书
因为 Whistle 要帮忙咱们解决所有的申请, 这其中也必然会有 https 申请, 所以肯定要导入 Whistle 的证书:
功败垂成, 开开心心的应用 测试环境域名
进行 本地开发
吧。
end
这次就是这样, 心愿与你一起提高。