You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useEffect更新状态但未触发重渲染问题排查

React中使用MediaDevices枚举设备后页面未正确渲染的问题修复

问题描述

尝试通过MediaDevices Web API的enumerateDevices方法加载并列出输入设备,使用React的useEffect钩子将设备信息存入state。React开发者工具显示inputs数组已有字符串列表,但页面未因状态更新正确渲染设备项。

原代码:

const App = () => {

  const [inputs, setInputs] = useState([]);

  useEffect(() => {
    let inputDevices = [];
    navigator.mediaDevices.enumerateDevices().then((devices) => {
      devices.forEach((device) => inputDevices.push(device.label));
    });
    setInputs([inputDevices]);
  }, []);


  return (
    <div>
      <ol>
        {inputs.map((device, index) => {
          return (
            <li key={index}>
              id:{index} - Device: {device}{" "}
            </li>
          );
        })}
      </ol>
    </div>
  );
};

输出截图:
输出截图1
输出截图2

编辑说明:setInputs([inputDevices])是失误,感谢提醒我Promise的异步特性:)


问题原因及修复方案

1. 异步执行顺序错误

enumerateDevices是异步Promise,原代码在then回调外部就调用了setInputs,此时inputDevices还未被填充设备数据。等到then回调执行时,state已经完成初始化,后续对inputDevices的修改无法触发React状态更新。

2. 数据结构错误

setInputs([inputDevices])将设备数组包裹成了二维数组,导致map遍历的是外层数组,每个device元素是整个设备列表数组,最终渲染出数组的字符串形式。

修正后的代码

const App = () => {
  const [inputs, setInputs] = useState([]);

  useEffect(() => {
    // 等待Promise完成后再处理数据并更新state
    navigator.mediaDevices.enumerateDevices().then((devices) => {
      const inputDevices = devices.map(device => device.label);
      // 直接传入一维设备数组
      setInputs(inputDevices);
    });
  }, []);

  return (
    <div>
      <ol>
        {inputs.map((device, index) => (
          <li key={index}>
            id:{index} - Device: {device}
          </li>
        ))}
      </ol>
    </div>
  );
};

补充:设备标签为空的处理

如果设备label显示为空,是因为浏览器的安全限制:必须先获取媒体权限(摄像头/麦克风),才能获取设备的真实名称。可以在枚举设备前先请求权限:

useEffect(() => {
  navigator.mediaDevices.getUserMedia({ audio: true, video: true })
    .then(() => navigator.mediaDevices.enumerateDevices())
    .then((devices) => {
      const inputDevices = devices.map(device => device.label);
      setInputs(inputDevices);
    })
    .catch(err => console.error('媒体权限请求失败:', err));
}, []);

内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:18:16