【问题标题】:React useState - setValue rerenders the component even though the value is the sameReact useState - setValue 重新渲染组件,即使值相同
【发布时间】:2019-02-20 14:16:48
【问题描述】:

我在自定义挂钩中使用useState 挂钩。

我正在调用从useState 返回的setValue 函数两次:

1) 在 onChange 事件之后

2) 在服务器通知组件发生更改之后。

事件的流程是:

  • onChange 事件(在组件中)触发 setValue = 重新渲染
  • 我正在使用 useEffect (=after rerender) 挂钩来更新更改的服务器 - 调用 API 函数来更新服务器
  • 我有一个自定义服务,它接收服务器的响应并通知组件
  • 当通知组件再次调用setValue 但在这种情况下,值相同,因此无需重新渲染。

我的问题是组件在收到更改通知后会重新渲染,即使收到的值相同。

我的代码:

增益分量

import * as React from 'react';
import { useDSPParamUpdate } from '../../../Hooks/useDSPParamUpdate';
import { ControlParamProps } from '../..';

const Gain = (props: ControlParamProps) => {

  let min: number = 0;
  let max: number = 0;


  const { paramId, controlId } = props;
  const { param, value, setValue } = useDSPParamUpdate({ controlId, paramId })

  if (param && param.range && param.range.length >= 2) {
    min = param.range[0];
    max = param.range[1];
  }

  /*calls the setValue from the hook*/
  const handleChange = (event: any) => {
    const newValue = event.target.value;
    setValue(newValue);
  }


  return (
    <div className="gain">
      {max}
      <input className="dsp-action range-vertical" type="range"
        min={min}
        max={max}
        value={value}
        onChange={handleChange} />
      {min}
    </div>
  );
}

export default Gain;

useDSPParamUpdate - 自定义挂钩

    import * as React from 'react';
        import { ControlParamProps } from '../dsp';
        import { dspService } from '../../core/services/dsp.service';

        export function useDSPParamUpdate(props: ControlParamProps) {

            const initValue = ...
            const [value, setValue] = React.useState(initValue);

            function updateDevice() {
                // calls some API func to update the server (sends the value)
            }

            // subscribes to server changes
            React.useEffect(() => {
                    // subscribrs to server notifications
                    let unsubscribe = dspService.subscribe((newVal) => setValue(newVal));
                return () => {
                    unsubscribe();
                };
            }, []);


            // sends data to the server after update
            React.useEffect(() => {
                updateDevice();
            }, [value]);

            return { param, value, setValue };
        }

【问题讨论】:

  • 在某些情况下,当将相同的值传递给状态设置器时,有一些优化可以避免重新渲染,但不能保证它不会重新渲染。有关更多详细信息,请在此处查看我的答案:stackoverflow.com/questions/54715188/…

标签: reactjs react-hooks


【解决方案1】:

通常情况下,如果 render() 被称为加时赛,这不是问题。

但如果你愿意,你可以通过检查值是否相同来保护调用setValue()

let unsubscribe = dspService.subscribe(
    (newVal) => 
        newVal !== value && setValue(newVal)
);  

可能有点冗长,但它与componentDidUpdate中通常使用的方法相同

请注意,useState 没有像 shouldComponentUpdate 那样提供任何逻辑。因此,如果您想以更具声明性的方式制作它,则必须将您的组件重构为基于类的 PureComponent 访问器。

【讨论】:

  • 我试过这个,但是当我调试它时,我看到value 总是有初始值......你的意思是什么“通常,如果 render() 被称为额外时间,这不是问题。 “?据我所知,额外的渲染是一个性能问题......
  • 很遗憾,我找不到对其进行测量的文章。但在后台 render() 不会对 DOM 进行操作,所以它应该非常快(直到你这里没有复杂的数学)。而且由于只有在“真实 DOM 与虚拟 DOM”之间存在差异时才会更新 DOM,我坚信您不需要关心额外的 render() 调用。
  • 至于“value 总是有初始值”,这真的很奇怪,因为你最终输出了它,所以如果它没有被改变,你应该已经提到
  • 这很奇怪..我认为这是一个错误...谢谢
猜你喜欢
  • 1970-01-01
  • 2021-03-10
  • 2017-05-17
  • 1970-01-01
  • 2021-01-07
  • 2020-06-02
  • 2020-08-15
  • 1970-01-01
  • 2022-06-18
相关资源
最近更新 更多