知乎 · 2021 下半年

2021 下半年 · 8 条
回答2021-08-31

useEffect监听了很多变量怎么办?

如果是简单的数据处理的话,我会用 @justjavac 答案里的做法:直接在 rendering 里处理数据。但是如果是计算密集的处理的话,我建议用 useMemo:

const { data: data1 } = //...

const parsedData1 = useMemo(
  () => data1?.data ? JSON.parse(data1.data) : undefined,
[data1]);

另外,如果答主一定要维护额外的 state 的话(例如在其他地方需要改变 state),那就把你那个大的 useEffect 拆分成四个小的 useEffect 吧。

再假设你想要等四个请求都完成再 setState 的话,可以:

const dataRef = useRef([data1, data2, data3, data3]);
dataRef.current = [data1, data2, data3, data3];

const isDone = data1?.data && data2?.data && data3?.data && data4?.data;
useEffect(() => {
  if (isDone) {
    setState1(dataRef.current[0]);
    setState2(dataRef.current[1]);
    setState3(dataRef.current[2]);
    setState4(dataRef.current[4]);
  }
}, [isDone])

这里只是提供思路,换我的话我是不会用四个 state 来维护状态。

♥ 9💬 2
回答2021-08-25

如何优雅解决前后端重复数据结构问题?

其他很多答案都提到了。关键在于用一种通用的语法来「对数据格式进行描述」,然后针对这种语法实现能够转译成不同编程语言的 code generator。走这条路的比较出名的有 protobuf、graphql 等。

例如,我们公司目前就 allin 了 graphql。通过 gql schema 来确定所有数据的格式,然后通过 code generator 来针对不同语言生成对应的实体/类型代码。如果数据格式需要更新的话,只需要更新 schema,然后不同端(例如前后端)再通过重新生成代码来同步变动。

很多人可能把 graphql 单纯当作前后端通讯的新协议,其实并不完全是的。graphql 本质上是一门数据描述/查询语言,需要数据交互的地方都可以用上,例如你可以在 web 端实现本地的 graphql over local storage。

当然,如果你不同端之间用同一门语言,把数据类型的代码抽到单独的 git repo 然后通过 submodule 的形式来共享也不是不行,不过不太建议(狗头

♥ 1💬 4
回答2021-08-17

大家都内推,内推还有什么意义?

先说结论:有用。

说说我在前东家知乎的经历。首先我是 @李明亮等100万人 明亮老师内推进去的,后来据我的一位直属 leader(也是当时的面试官)说,我当初面试的效果不是很好,但是还是给机会了(狗头。

而后来在知乎的生涯里,我也内推了好几位小伙伴。其中有两位小伙伴也是面试结果不太好,但是因为我个人对他们比较熟悉,所以跟面试官商量了下也都愿意再给一次机会,后来他们两也都最终收到了 offer。

♥ 0💬 3
回答2021-08-15

有哪些优秀的个人网站?

自荐一下我的个人网站(记得打开声音

neko岛

使用 PixiJS + TiledMap 实现的小岛

  • 为了兼顾没有键盘的移动端,所以选择了使用鼠标/触摸点击的方式进行交互
  • shader 滤镜: sepia + bulgePinch + brightnessContrast + vignette + noise
  • 寻路算法: PathFinding.js
  • 地图编辑器: Tiled

灵感来自湾湾一个组织搭建的在线网站(因为涉及政治,这里就不分享更多信息了

源码在我的 GitHub 上可以找到

♥ 5💬 5
回答2021-08-14

使用React hooks如何只让下面这段代码的子组件只render一次?

作为给 ant design 贡献过代码的人,可以告诉你 antd 内部是用的 forwardRef 和 useImperativeHandle 来实现这个效果。这也是目前仅通过内部 hooks 来实现的最正确的做法。

看了一圈这个问题下的回答,只有 @maxcalibur 回答到这两个 function,但是却一个赞都没(黑人问号)。其他人要么直接说没法实现,要么通过各种绕弯子来实现,。。

另外拓展一下,用我这个基于观察者模式共享 state 的库来做也是可以实现的:

GitHub - nekocode/use-shared-state: React hook for sharing state or notifying event between components. Just like the widget controller in Flutter.

去看一下我写的 readme 下的 live example 就知道了,目前已在几家大大小小的公司中投产了。

还有一些其他不算方法的方法:

  1. 子组件直接用父组件传的 props 而不是用内部自己维护的 state 来渲染,然后通过 callback 反馈给父组件来刷新传进来的 props 也是可以的,但是子组件一定要自己维护 state 的情况就不能这么用了。
  2. 再另外,父组件渲染时改变一下子组件的 key 来强制重新创建 dom 也是可以实现题主要的效果的,只不过性能上会更差(狗头)。

那些说没法实现的不是被打脸么。

========= 08/17 更新 =========

感谢 @Dcab 和 @Liuyl 在评论区的讨论。@maxcalibur 的答案里之所以组件 B 没包 memo 也能最终只渲染一次,是因为 react 框架的 auto batchupdate 将两次 setState 优化为只 update 一次父组件了。

另外补充一下,forwardRef 和 useImperativeHandle 是用来将子组件的内部状态或方法挂载到 ref 上(通常在父组件创建)。

而要实现父组件刷新时子组件不跟随刷新的话,目前比较好的选择有:

  1. 用 memo 方法包裹子组件,然后确保传给子组件的 props 不变。
  2. 将子组件的创建(createElement)放到父组件的 render function 外,这也是 constate 这个库的基本原理之一,举个例子:
// 仅为大概,其余细节请自行脑补补齐
const A = React.forwardRef((_, ref) => {
  useImperativeHandle(ref, ...);
});
const B = React.forwardRef(({ children }, ref) => {
  const onClick = () => { ref.update() }
  return <>
    {children}
  </>
});
const App = () => {
  const ref = useRef(null);
  return <B ref={ref}>
    <A ref={ref} />
  </B>
}
♥ 13💬 18
回答2021-08-13

新版react中,usecallback和usememo是不是值得大量使用?

个人认为应该尽量使用 useMemo 和 useCallback。

所有 rendering 中创建的 callback 尽量用 useCallback 包起来、对象的创建尽量用 useMemo 包起来。

hooks 具有依赖传递性,这么做主要是为了避免触发可能隐藏在某个子组件里的多余的副作用,以及副作用最终可能造成的 re-render(甚至死循环)。

试想一下你写了个组件,props 里需要传进一个 callback 来响应 dom 事件。一开始不用 useCallback 可能没问题,但是某天当你突然要改成在 useEffect 里去响应这个 callback 的话那就崩了,你不得不把上层所有组件传参时都用 useCallback 包一下,如果你这个组件在很底层,那么扩散范围将特别大,更不说跨 package 这种更糟糕的情况了。

这类情况还是很常见的,为了减少心智成本(对于究竟要不要/能不能用的患得患失)、以及不必要的埋坑,尽量使用 useMemo 和 useCallback 很有必要。

♥ 1💬 20
回答2021-08-11

为什么很多大厂优先考虑使用 React 而不采用 Vue?

没深度用过 vue(作为替代我会选 svelte,狗头

但就 vue2 而言(这里不讨论 vue3),单单是对 typescript 支持不太行这一点,就注定了在大型项目上不会被优先考虑。

其他一些思考:

  • react 的 functional component 以及 hooks 配合起来的抽象能力极强,用「函数」(已经是能对组件进行拆分、抽象的最小单位了)就能承载组件的渲染、以及散落在 class component 不同生命周期但却相关联的逻辑。
  • react 的 jsx 比 vue 的模板语言描述能力更强,因为 jsx 是图灵完备的(但模板语言也有好处:更容易做编译期和运行时的优化)。

其他一些比较就不说了。个人感想是 react 是在引领行业,而 vue 则是实用主义,看菜下饭吧。

♥ 3💬 9
回答2021-08-07

既然已经有了node.js,那么,现实中还会有前端工程师这么个职业么?

想啥呢,nodejs 只能节省了你再学习一门语言的时间,而这个时间成本很低的,相对而言,领域知识的学习成本才是最高的(狗头

有对应编译器 / 解释器 / 运行时的话,你甚至可以用任何语言去做任何事情。nodejs 的出现更大的意义是帮助完善了前端工具链,让前端工程师有能力对前端进行工程化。

♥ 1💬 0