Typescript 类作为 React 状态,重新渲染

Posted

技术标签:

【中文标题】Typescript 类作为 React 状态,重新渲染【英文标题】:Typescript class as React state, rerender 【发布时间】:2021-03-25 07:49:45 【问题描述】:

我有以下功能组件:

const Player = () => 
  const [spotifyPlayer, setSpotifyPlayer] = React.useState<SpotifyPlayer | null>(null);

  return (
    <SongControls togglePlay=togglePlay isPlaying=spotifyPlayer.isPlaying />
  );
;

SongControls 组件负责显示正确的控制按钮(开始/暂停):

const SongControls: React.FC<Props> = ( isPlaying : Props) => 
  return (
    isPlaying ? (
      <Pause style=iconBig onClick=togglePlay />
    ) : (
      <PlayArrow style=iconBig onClick=togglePlay />
    )
  );
;

Player 组件中的spotifyPlayer 状态是具有isPlaying 类型为boolean 的字段的类。它还有一个定义为togglePlay() 的函数,用于切换isPlaying

问题是当togglePlay() 被调用时,React 不会重新渲染组件。我明白为什么(因为 SpotifyPlayer 的实例没有改变,所以你不应该直接更新反应状态)。

我无法调用setSpotifyPlayer() 来更新状态,原因有两个:

SpotifyPlayer 的实例负责切换isPlaying 当我使用 js 解构更改状态时,我丢失了 spotifyPlayer 状态的原型,并且该功能将不再可用。

我想不通。

【问题讨论】:

【参考方案1】:

您对问题的理解是正确的。您不能依赖对 SpotifyPlayer 对象内部状态的更改来触发重新渲染。我建议使用本地状态来存储 isPlaying 的值并根据对该值的更改更新 SpotifyPlayer

如果播放器对象有某种onChange 监听器,那么我会使用播放器来设置本地状态,而不是相反。

我不确定播放器来自哪个包,所以我假设这个界面:

class SpotifyPlayer 
  isPlaying: boolean = false;
  play(): void 
    this.isPlaying = true;
  
  pause(): void 
    this.isPlaying = false;
  

我们可以使用useRef 来存储对播放器对象的一致引用。

const spotifyPlayer = React.useRef<SpotifyPlayer>(new SpotifyPlayer()).current;

我们会将isPlaying 的值存储在本地状态中。我们可以从玩家那里得到初始值。

const [isPlaying, setIsPlaying] = React.useState(spotifyPlayer.isPlaying);

为了使isPlaying与播放器保持同步,我们可以使用useEffect

const togglePlay = () => setIsPlaying(!isPlaying);

React.useEffect(() => 
  if ( isPlaying && ! spotifyPlayer.isPlaying ) 
    spotifyPlayer.play();
   else if ( ! isPlaying && spotifyPlayer.isPlaying ) 
    spotifyPlayer.pause();
  
, [spotifyPlayer, isPlaying]);

但如果togglePlay 是唯一会更改值的函数,那么我们可以处理该函数中的更改。

const togglePlay = () => 
   if (isPlaying ) 
       spotifyPlayer.pause();
       setIsPlaying(false);
    else 
      spotifyPlayer.play();
      setIsPlaying(true);
   

【讨论】:

以上是关于Typescript 类作为 React 状态,重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

我想在辅助函数中操作 React 类组件中存在的状态。我想在 Typescript 中实现相同的目标

Typescript React 空函数作为 defaultProps

使用 Typescript 在 React 中重定向

React Router DOM 历史对象导致 Typescript 错误

React 状态管理:上下文 API 作为全局存储

如果用户登录 React 和 Typescript,则在刷新时重定向到仪表板