【问题标题】:Re rendering state after setting state设置状态后重新渲染状态
【发布时间】:2019-03-25 14:19:14
【问题描述】:

我想获取数据,如果获取时出错。我想等待 1000 秒,然后再次获取数据。

问题是在方法 settingTimeout() this.setState({timerStatus: true});我期待重新渲染整个应用程序并在 console.log 中渲染超时。但由于某种原因,它没有这样做。我尝试在 settingTimeout() 中使用 this.forceUpdate();没有太多的运气。 React similiar example

this.state = {
      retryTimer: 1000,
      timerStatus: false,
    }
  }
  componentDidMount(){
    if(this.state.timerStatus){
      console.log('timeout');
    }
    this.newGame();
  }

  newGame =() => {
    Axios.get(
      this.state.apiBase + 'nexGame',
      this.state.headers
    )
    .then(response =>{
     console.log(response)
      }
    })
    .catch(error =>{
      this.settingTimeout();
    })
  }
  settingTimeout = () =>{
    this.setState({timerStatus: true});
    if(this.state.retryTimer === 0){
      this.newGame();
    }
  }

【问题讨论】:

  • this 可能不是您所期望的。将newGamesettingTimeout 制作成箭头函数,看看是否可行。 newGame = () => { ... }; settingTimeout = () => { ... };
  • retryTimer 在哪里倒计时?你设置了超时但没有指定时间间隔?
  • 我没有包括设置间隔,因为首先我需要解决打印 console.log(timeout);
  • 我认为它没有被记录的原因是因为 setState 还没有完成,因为它是一个异步操作,在 componentDidUpdate 中你应该能够看到结果
  • 是的,你说得对。将 if 语句放入 componentDidUpdate 打印超时

标签: javascript reactjs axios


【解决方案1】:

您可以尝试以下方法(解释在小提琴下方):

let counter = 0;

class App extends React.Component {
    timer;
    
    constructor(props) {
        super(props);
        
        this.state = {
            data: "",
            loading: true,
            fetchError: false            
        }
    }
    
    componentDidMount() {
        /* Simulating a fetch with setTimeout. */
        const random = Math.floor(Math.random() * 1000) + 100;
        
        setTimeout(() => {
            /* Here you would write .then(). */
            if (counter === 2) {
                this.setState({loading: false});
            }
            
            /* Here you would write .catch(). */
            if (counter === 0) {
                this.setState({fetchError: true});
                this.timer = setInterval(this.handleFetch, 1000);
            }
            
            counter++;
        }, random);
    }
    
    handleFetch = () => {
        /* Simulating a fetch with setTimeout. */
        const random = Math.floor(Math.random() * 1000) + 100;
        setTimeout(() => {
            /* This would be the then(), where you save the data. */
            if (counter === 2) {
                clearInterval(this.timer);
                this.setState({loading: false, fetchError: false, data: "YES!!"})
            }
            
            /* In this case, if the fetch fails, you do nothing. */
                                  
            counter++;
        }, random);
    }
    
    render() {
        const {fetchError, loading, data} =  this.state;
        return (
            <React.Fragment>
                {loading && fetchError && <p>Error in Fetch</p>}
                {loading && !fetchError && <p>Loading</p>}
                {!loading && !fetchError && <p>{this.state.data}</p>}
           </React.Fragment>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
@import url(https://fonts.googleapis.com/css?family=Montserrat);

body {
    font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id='root'></div>

首先,我使用setTimeout 来模拟提取。此外,为了模拟提取错误,我使用了counter 变量:当它达到2 的值时,则认为提取正确,否则认为失败。
说了这么多,怎么回事?在componentDidMount 中,您运行您的第一次提取:而不是if (counter === 2),您应该编写提取的.then()(因此,当它正确运行时)。在该回调中,您只需将 this.state.loading 设置为 false
否则,您应该编写catch() 语句而不是if (counter === 0):在这种情况下,您创建interval 调用每个handleFetch() 函数1000ms。请注意,在本例中,您将 this.state.fetchError 设置为 true:这样您可以向用户提供更好的反馈。

现在,在handleFetch() 内部执行fetch: 再次,如果它正确结束,您可以将this.state.loadingthis.state.fetchError 设置为false,并保存状态中的数据。 否则,您只需等待另一个 1000ms 进行下一次提取。

【讨论】:

    【解决方案2】:

    如果前一个电话失败,您似乎想每隔 1 秒再拨打一次电话,对吧?

    我不确定您是否需要重新渲染您的应用才能做到这一点。如果你想重做这个调用,你可以使用组件 https://reactjs.org/docs/react-component.html#updating 的 react 生命周期

    与:

    shouldComponentUpdate(nextProps, nextState) {
      if(this.nextState.timerStatus = true) { 
        setState({ timerStatus: false });
        this.newGame();
    }
    

    并且在你的函数 settingTimeout 上设置一个超时时间,当经过 1s 时,将 timerStatus 的状态更改为 true。 React 会监视这个,将 timerStatus 设置为 false 并重新调用。如果通话正常,您将得到答案,否则您将再次等待 1 秒并重新拨打电话,等等。

    【讨论】:

    • 我不断收到 timerStatus is not defined 你确定 timerStatus = false 行是正确的吗?
    • 我认为应该是当前状态下的 timerStatus -> setState({ timerStatus: false })
    • 是的,正如@ThibaultGobert 所说,它当然是 setState,我回复得太快了
    猜你喜欢
    • 2021-06-11
    • 2019-09-16
    • 2023-03-09
    • 1970-01-01
    • 2023-02-09
    • 2019-02-18
    • 2020-11-01
    • 2016-04-22
    • 2019-11-09
    相关资源
    最近更新 更多