1. React异步回调无法获取最新状态的问题

异步回调无法获取setState的新状态(回调函数形成了闭包,访问的还是旧状态的作用域),比较好的方法是使用useRef。若还达不到理想中的效果,也可能是多个事件回调函数的执行顺序和你想象中的不一样,可以通过添加setTImeout定时器来保证指定操作只在目标状态更新之后执行。

也可以考虑在useEffect的回调函数中处理业务逻辑。其回调函数在首次渲染时执行,在依赖项发生变化时重新执行。需要注意的是,useEffect的回调函数中return指定的回调函数,在每次依赖项发生变化时,访问的还是旧状态的作用域,不是最新的状态。

2. [浏览器渲染bug]table组件在特定情况下导致页面高频闪烁卡顿的问题

触发条件不是非常明确。

大致是当table被放在一个overflow: auto(或scroll)的div中,且没有指定固定的列宽度,而是自动动态计算,那么当可以滚动时,就会引发浏览器高频率地触发布局与渲染,导致CPU占用极高,页面闪烁、出现白块、严重卡顿等。

且innerWidth和innerHeight越大,页面闪烁卡顿越严重,性能占用越高。

该问题目前没有较好的根治方法。只能尝试缩小table的宽高,在视口较大时,考虑不使用滚动来处理长table,可以考虑分页处理。

GitHub有相关的issue

3. 反转动画的一个坑

比如你定义了一个CSS动画 popup

@keyframe popup{
    '0%': {
        transformOrigin: 'top',
        opacity: 0,
        transform: 'scale(0.2)',
    },
    '100%': {
        transformOrigin: 'top',
        opacity: 1,
        transform: 'scale(1)',
    },
}

然后你给一个组件添加该动画

animation: popup .3s ease forwards;

那么渲染该组件时,会执行该动画,因为用了forwards,所以动画结束后会保持在100%的时间轴状态(保持动画结束的状态)。

这个时候,如果你想通过js修改该组件的动画为同一个动画popupreverse倒转播放,比如修改后为:

animation: popup .3s ease reverse forwards;

则实际上该组件不会正常播放倒转动画,而是缺少过渡,直接闪烁到最终状态或根本不播放。

其中一个解决方法是,将逆转动画另外设置一个新的动画名,然后切换为这个动画来播放即可。

另外需要注意

设置了display: none;之后会重置状态,重置动画时间线(now_time)

但设置visibility: hidden;不会重置。

另外,常用的动画设置:

  • 添加alternate infinite是循环往复动画
  • 添加forwards是执行一次 保持在最后状态

4. React Webpack项目 怎么通过process.env.NODE_ENV区分开发和生产环境

在React Webpack项目中,可以通过process.env.NODE_ENV来区分开发环境和生产环境。Webpack在构建项目时,会为每个环境设置不同的process.env.NODE_ENV变量值。

在开发环境中,通常设置NODE_ENV为"development",而在生产环境中设置为"production"。您可以利用这个环境变量来在项目中采取不同的行为,例如加载不同的配置文件、启用优化等。

在React项目中,通常我们会使用process.env.NODE_ENV来实现条件编译、加载不同环境的配置等。

5. SourceMap配置

webpack.config.js中添加该配置:

const isDevelopment = process.env.NODE_ENV === 'development';

module.exports = {
    // ...
    devtool: isDevelopment ? "inline-source-map" : false,
    // ...
}

并在部署命令中配置环境,比如在本地调试的命令中添加NODE_ENV=development

"webpack:dev": "NODE_ENV=development webpack-dev-server --mode development",

PS:这里虽然后面有--mode development,但是不添加NODE_ENV=development的话,在webpack.config.js中是无法获取到process.env.NODE_ENV的。

6. position: fixed 在filter下失效的问题

如果父元素中存在filter属性,子元素使用position: fixed将会相对于父元素定位,不再相对 viewport进行定位。

这个特性无法避免,只能曲线救国。

产生原因

产生这个问题的原因就是:

当 filter 不为 none 的时候,如果该元素或者其子元素具有 absolute 或 fixed 属性,那么它会为其创建一个新的包含块/容器,会造成该 absolute 或 fixed 元素的定位发生变化(就是改变了 absolute 或 fixed 元素的定位<父>元素,变成新创建的元素)。

以上面的例子说明,当在 body 标签中使用了 filter 属性后, filter 就会生成一个新的包含块,其位置大小和 body 一样,然后 fixed 元素就会根据这个包含块进行定位,所以我们会看到 fixed 元素失去原有的特性;

但是,如果 filter 作用在根元素(即 html 标签)时,它是不会为 absolute 或 fixed 子元素创建新的包含块的。

参考: https://drafts.fxtf.org/filter-effects/#FilterProperty

所以解决方案也就很简单了,只需要将 filter 属性放在 html 标签上就好了

相关资料

7. useEffect获取到后端数据之前 前端怎么展示loading状态 以避免闪烁等不良体验

因为useEffect是在渲染完成之后异步执行的,所以会出现页面状态更新导致的视图闪烁等问题。

解决方法

  1. 使用同步任务hook useLayoutEffect可以在渲染之前就get到数据;
  2. 可以用loading图标/动画来代替加载数据前的样式,可以用gsap加一些过渡动效。

8. 善用React.Children.toArray()

React.Children.toArray 是一个React API,用于将props.children转换为一个扁平数组,同时为每个子元素分配一个唯一的key。这在你需要对子元素进行排序、切片或者其他数组操作时非常有用。例如,如果你有一个<Parent>组件,它接收多个<Child>组件作为子元素,并且你想对这些子元素进行排序或过滤,那么你可以使用 React.Children.toArray 来简化这个过程。

使用示例

[> Basic Trail - React Spring示例< ]

import React, { useState } from 'react'

import styles from './styles.module.css'

const Trail: React.FC<{ open: boolean }> = ({ open, children }) => {
  const items = React.Children.toArray(children)

  return (
    <div>
    <!-- ... -->
    </div>
  )
}

export default function App() {
  const [open, set] = useState(true)
  return (
    <div className={styles.container} onClick={() => set(state => !state)}>
      <Trail open={open}>
        <span>Lorem</span>
        <span>Ipsum</span>
        <span>Dolor</span>
        <span>Sit</span>
      </Trail>
    </div>
  )
}

9. html2canvas 捕获到的某些元素是空白的

如果不是没有正确配置useCORS导致的,那么大概率是因为你要捕获的元素有渐入效果,看是不是有opacity从0到1的过渡效果;或者离屏渲染后立刻捕获的话,ecahrts、G2plot等自带的图表渐入动画没有关闭或没有在图表绘制完成的钩子中调用html2canvas的方法。


A Student on the way to full stack of Web3.