【问题标题】:Why does React rerender when the state is set to the same value the first time via an onClick event on DOM, but not react-native?当状态第一次通过 DOM 上的 onClick 事件设置为相同的值时,为什么 React 会重新渲染,而不是 react-native?
【发布时间】:2022-01-15 15:01:42
【问题描述】:

我有一个我认为是证明状态变化的简单测试,我有另一个测试通过计时器进行更改并且它工作正常(至少我是这样假设的)但是这个由click触发事件,它没有通过我的重新渲染检查。

  it("should not rerender when setting state to the same value via click", async () => {
    const callback = jest.fn();
    function MyComponent() {
      const [foo, setFoo] = useState("bir");
      callback();
      return (<div data-testid="test" onClick={() => setFoo("bar")}>{foo}</div>);
    }

    const { getByTestId } = render(<MyComponent />)
    const testElement = getByTestId("test");
    expect(testElement.textContent).toEqual("bir");
    expect(callback).toBeCalledTimes(1);

    act(() => { fireEvent.click(testElement); });
    expect(testElement.textContent).toEqual("bar");
    expect(callback).toBeCalledTimes(2);

    act(() => { fireEvent.click(testElement); });
    expect(testElement.textContent).toEqual("bar");
    expect(callback).toBeCalledTimes(2); // gets 3 here
  })

我尝试使用代码框 https://codesandbox.io/s/rerender-on-first-two-clicks-700c0 来做同样的事情

我在查看日志时发现它会在前两次点击时重新渲染,但我的期望是在第一次点击时重新渲染,因为值是相同的。

我也通过a snack 在 React native 上做了类似的事情,它工作正常。只有一个重新渲染。所以它可能是特定于 React-DOM 上的 onClick #22940

【问题讨论】:

  • "请注意,React 可能仍需要在退出之前再次渲染该特定组件。这不应该是一个问题,因为 React 不会不必要地“深入”到树中。如果你是在渲染时进行昂贵的计算,您可以使用 useMemo 对其进行优化。”来自 React 文档:reactjs.org/docs/…
  • 问题是为什么要重新渲染?
  • 为了确保所有更改都已完成,这就是 react 的工作方式,正如他们在文档中所说,这不应该是一个问题
  • 但值没有变化。正如他们的文档中所述,他们使用 Object.is 你不能得到任何比使用相同的 const

标签: javascript reactjs jestjs


【解决方案1】:
  • 实现 shouldComponentUpdate 以仅在 state 或 属性变化。

  • 这是一个使用 shouldComponentUpdate 的示例,它可以工作
    仅用于这个简单的用例和演示目的。当这个
    使用时,组件不再在每次单击时重新呈现自身,并且 在第一次显示时和单击一次后呈现。

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      if (this.state == null)
        return true;
  
      if (this.state.test == nextState.test)
        return false;
        
      return true;
  },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

【讨论】:

  • 我使用的是功能组件而不是类组件。
猜你喜欢
  • 2021-05-21
  • 2017-01-14
  • 1970-01-01
  • 2021-04-21
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
相关资源
最近更新 更多