2017-07-06 116 views
1

我有一個方法,提供一個圖標(字體真棒圖標)內提供的容器。圖標的渲染可以通過用戶點擊特定的div來實現,或者通過程序自身在模仿用戶點擊特定div時自動調用渲染功能。ReactDOM.render在特定情況下無效?

爲了更好地理解這一點。我創造了這個所謂的TicTacToe遊戲。有可能玩player vs playerplayer vs cpu。如果兩個玩家都在玩,那麼沒有問題,一切都很好。

現在,當玩家玩CPU時,會發生一些奇怪的事情。如果第一個玩家是CPU,那麼它的第一個動作不會呈現(圖標不會出現)。但其餘的看起來很好。

如果我讓兩個玩家都是CPU(CPU對另一個CPU玩遊戲),那麼沒有任何東西會被渲染。難道說ReactDOM.render如果他們發生得太快?;)

因此,這裏的程序(遊戲的一部分)忽略的變化:

$(document).ready(function() { 
    const ICONS_CLASSES = { 
     x: 'fa fa-times fa-lg', 
     o: 'fa fa-circle-o fa-5x' 
    } 
    function renderMove(el, turn){ 
     const classes = ICONS_CLASSES[turn]; 
     ReactDOM.render(
      React.createElement('span', {'className': classes}), 
      el 
     ) 
    } 
... 
... 
}); 

而且,這裏是一個由程序本身來模仿調用的函數點擊遊戲中的一個特定的div(好讓說CPU「點擊」它):

function clickPosition(el, tic){ 
    if(tic.state == 'running'){ 
     // Save which player played, because after playing move, it will 
     // switch turn for another player. 
     const type = tic.turn.type; 
     const res = tic.play(el.id); 
     if(res != 'invalid') 
      renderMove(el, type); 
     updateInfo(tic.info) 
     // Add start block to be able to play again. 
     if(tic.state == 'stopped'){ 
      // Highlight win combo if there is any 
      if(tic.winCombo) 
       highlightWin(tic.winCombo) 
      toggleEl($('#start')) 
     } 

    } 
} 

所以弄不好呈現爲此前曾表示,不會令所有的時間(以CPU播放時)。

但是,如果我改變渲染到這一點:

el.innerHTML = `<span class="${classes}"></span>`; 

然後它呈現的任何圖標就好了。不管是否玩遊戲player vs player,cpu vs player,player vs cpu甚至cpu vs cpu(在這種情況下,所有的圖標立即渲染,因爲最終結果總是繪製)。

是否有一些與ReactDOM.render

P.S.如果你有興趣,你可以在這裏找到完整的代碼(目前它可以播放cpu vs player,這意味着首先播放CPU,並且由於它是用ReactDOM.render呈現,所以第一個動作將是隱形的,其他人應該顯得很好):https://codepen.io/andriusl/pen/qjyBdB

回答

1

看起來像ReactDOM.render一切正常。但是我猜猜渲染髮生得太快,這種說法是正確的。但從另一個地方。

有一個函數(我沒有提到的問題)清除所有呈現的圖標。遊戲開始後就會清楚。當玩家正在玩時,則沒有問題,因爲結算會在稍後發生,用戶點擊div。但是,當CPU執行該操作時,它的速度會更快,因此它在調用清除之前輪到它,並清除該移動圖標。

所以技術上呈現,但它會立即刪除,看上去就像它從來沒有顯示,至少對我們人類:)

所以修復是tic.start前搬遷ReactDOM.unmountComponentAtNode。然後它在開始比賽之前總是清除,而不是在之後(或在開始另一場比賽之前)清除。

$('#x, #o').on('click', function() { 
    const second = {'x': 'o', 'o': 'x'}; 
    // Clear filled positions if any. 
    let positions = document.getElementsByClassName('pos'); 
    _.each(positions, pos => { 
     ReactDOM.unmountComponentAtNode(pos); 
    }) 
    tic.start(this.id, second[this.id]); 
    toggleEl($('#start')); 
    updateInfo(tic.info); 

}) 
+0

感謝您分享您的解決方案。今天早上我遇到了你的問題,但沒有時間真正研究它。我必須說,你可能沒有得到最好的用法(使用嵌套組件,狀態,道具,反應的事件監聽器,並讓反應來處理掛載/卸載),但我確實發現你的方法非常有趣(以一種好的方式)。 :) – DonovanM