首页 > 解决方案 > React 状态在渲染方法和页面上实际显示的内容之间不同步

问题描述

我需要访问我的 React 应用程序之外的 DOM 元素,它的加载速度可能比我的应用程序慢。然后我需要更新我的状态来渲染一些不同的东西。为此,我使用从 componentDidMount() 启动的递归函数轮询 DOM 元素。我看到一个奇怪的问题,一旦找到元素并且我更新了状态,事情就会不同步。在渲染函数中,我的 console.log() 显示了更新后的状态值,在 React 开发者工具中我看到了更新后的状态值,但在实际渲染的页面上,我看到的仍然是旧的状态值。

代码:

// initially doesn't exist. Added to the DOM after 3 seconds
let slowElement = document.querySelector('.external-dom-element')

class App extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      showFoundSlowElementMessage: false,
      slowElementCheckMaxAttempts: 5,
      slowElementCheckCount: 0,
    }

    this.checkForSlowElement = this.checkForSlowElement.bind(this)
  }

  componentDidMount () {
    this.checkForSlowElement()
  }

  checkForSlowElement () {
    slowElement = document.querySelector('.external-dom-element')

    if (slowElement !== null) {      
      console.log('found') // element found, show message

      this.setState({
        showFoundSlowElementMessage: true
      })
    } else {      
      console.log('not found') // element not found, increment count and check again after delay

      this.setState({
        slowElementCheckCount: this.state.slowElementCheckCount + 1
      }, () => {
        if (this.state.slowElementCheckCount < this.state.slowElementCheckMaxAttempts) {
          window.setTimeout(this.checkForSlowElement, 1000)
        }
      })
    }
  }

  render() {
    const foundSlowElement = this.state.showFoundSlowElementMessage
      ? <p>Found slow element</p>
      : <p>No sign of slow element, checked {this.state.slowElementCheckCount} times</p>

      // null until it is added to the page
      console.log(foundSlowElement)

      return (
        <div>
          <h1>Hello</h1>
          {foundSlowElement}
        </div>
      );
    }
  }
}

ReactDOM.render(<App />, document.getElementById('react-target'));

// Simulate slow element by adding it to the DOM after 3 seconds
window.setTimeout(() => {
  const root = document.getElementById('root');
  const newElement = '<div class="external-dom-element">slow element</div>';
  root.innerHTML += newElement;
}, 3000)

codepen 上的工作示例

标签: javascriptreactjs

解决方案


我自己想通了。它与我的组件无关,破坏它的是演示本身。当我通过附加根元素的内部 html 来模拟慢速元素时:

  root.innerHTML += newElement;

它重新解析整个元素并且 React 丢失了它之前设置的所有事件处理程序等。

这个线程帮助了我


推荐阅读