簡體   English   中英

兒童使用地圖和Redux時觸發重新渲染

[英]Children prop triggering re-render when using map and redux

我正在使用Redux創建一個測驗應用程序,其中包括帶有一些嵌套字段的表單。 我剛剛意識到(我認為),如果我使用children道具,則每次按下輸入字段都會觸發重新渲染,即按如下方式設計應用程序:

const keys = Object.keys(state)

<QuizContainer>
  {keys.map(key => 
    <QuizForm key={key}>
        {state[key].questions.map(({ questionId }) => 
           <Question key={questionId} questionId={questionId}>
               {state[key]questions[questionId].answers.map(({ answerId })=>
                   <Answer answerId={answerId} key={answerId} />
               )}
           </Question>
        )}
    </QuizForm>
  )}
</QuizContainer>

QuizContainer使用mapStateToProps和mapDispatchToProps連接到redux,並吐出一個數組數組,這些數組中都包含對象。 商店結構是根據Dan Abramov的“ Redux嵌套指南”(使用類似於關系數據庫的商店類型)設計的,可以這樣描述。

{
    ['quizId']: {
        questions: ['questionId1'],
        ['questionId1']:
            { question: 'some question', 
                answers: ['answerId1', 'answerId2']
            },
        ['answerId1']: { some: 'answer'},
        ['answerId2']: { some: 'other answer'}
 }

上面的代碼可以正常工作,沒有任何錯誤,但是會引發大量的重新渲染,但是只有在我使用合成語法的情況下,以上代碼才能正常工作。 如果我將每個組件放到另一個組件中(即不使用props.children),而只是發送quizId-key(以及其他id-number作為props),它將按預期工作-無需瘋狂地重新渲染。 為了清晰起見,當我執行以下操作時它會起作用:

// quizId and questionId being passed from parent component's map-function (QuizForm)

const Question ({ answers }) => 
    <>
      {answers.map(({ answerId }) => 
        <Answer key={answerId} answerId={answerId} />
      )}
    </>

const mapStateToProps = (state, { questionId, quizId }) => ({
    answers: state[quizId][questionId].answers
})

export default connect(mapStateToProps)(Question)

但為什么? 兩者有什么區別? 我意識到其中一個是作為道具傳遞給父母的,而不是被渲染為那個父母的孩子,可以這么說,但是為什么這樣做最終會帶來不同的結果呢? 它們不應該相等但可以使用更好的語法嗎?

編輯:我現在可以驗證兒童道具是否引起了問題。 設置

shouldComponentUpdate(nextProps) {
    if (nextProps.children.length === this.props.children.length) {
       return false
       } else {
       return true
    }
}

解決問題。 但是,這似乎是一個非常好的黑匣子解決方案,不太確定我現在錯過了什么...

使用render prop模式時,每次組件渲染時都在有效地聲明一個新函數。 因此, props.children之間的任何淺層比較都會失敗。 這是該模式的一個已知缺點 ,您的“黑匣子”解決方案是有效的。

好吧,我明白了:

我做了兩件事:

  1. 我將頂部組件連接到狀態,如下所示:mapStateToProps(state)=>({keys:Object.keys(state)})。 我以為對象函數將返回“靜態”數組並阻止我偵聽整個狀態,但事實證明我錯了。 顯然(現在對我來說),每次更改狀態時,我都會得到一個新的數組(但具有相同的條目)。 現在,我將它們存儲在一個完全獨立的屬性quizIds中。

  2. 我將地圖功能放在不好的地方。 我現在繼續像這樣渲染QuizContainer:

      <QuizContainer> {quizIds.map(quizId => <QuizForm> <Question> <Answer /> </Question> </QuizForm> )} </QuizContainer> 

然后,我渲染我的孩子數組,為他們注入道具以便能夠單獨使用connect,如下所示:

    {questions.map((questionId, index) => (
      <React.Fragment key={questionId}>
        {React.cloneElement(this.props.children, {
          index,
          questionId,
          quizId
        })}
      </React.Fragment>
    ))}

如果您決定將多個元素作為子元素,則最后一段代碼將不起作用。 無論如何,看起來更干凈,現在效果更好! :D

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM