簡體   English   中英

通過 React 中的嵌套組件向上傳遞數據

[英]Passing data up through nested Components in React

以一個想法開始; 我想我可能需要一個遞歸組件,但這超出了我目前使用原生 js 和 React 的能力,所以我覺得此時我對 React 有了瑞士奶酪的理解。

問題

我有一個包含元metafield對象的元metafields數組,其結構如下:

{
  metafields: [
    { 0: 
      { namespace: "namespaceVal", 
        key: "keyVal", 
        val: [
          0: "val1", 
          1: "val2", 
          2: "val3" 
        ]
      }
    }, 
    ...
  ]
}

我的代碼將元metafields映射到卡片中,並且在每張卡片中都有一個組件<MetafieldInput metafields={metafields['value']} />並且在該組件中,值數組被映射到輸入字段。 整體看起來像:

// App
render() {
  const metafields = this.state.metafields;
  return (
    {metafields.map(metafield) => (
      <MetafieldInputs metafields={metafield['value']} />
    )}
  )
}

//MetafieldInputs
this.state = { metafields: this.props.metafields}

render() {
  const metafields = this.state;
  return (
    {metafields.map((meta, i) => (
      <TextField 
        value={meta}
        changeKey={meta}
        onChange={(val) => {
          this.setState(prevState => {
            return { metafields: prevState.metafields.map((field, j) => {
              if(j === i) { field = val; }
              return field;
            })};
          });
        }}
      />
    ))}
  )
}

到目前為止,一切都顯示正確,我可以更改輸入! 但是,更改一次一個,因為我按了一個鍵,然后我必須單擊回輸入以添加另一個字符。 似乎一切都被重新渲染,這就是為什么我必須單擊回輸入進行另一次更改。

我可以以這種方式使用組件嗎? 感覺就像我正在努力嵌套組件,但我讀過的所有內容都說不要嵌套組件。 我是不是把這個問題復雜化了? 我唯一的解決方案是撕掉 React 部分並將其用於純 javascript。

指導將不勝感激!

您需要在應用程序級別執行 onChange。 您應該將 onChange 函數傳遞給 MetaFieldsInput 並在渲染時始終使用this.props.metafields

我的建議是取出 onChange 處理程序的源代碼,這樣可以更容易地理解代碼。

主要是 React 不會在setState()調用后立即更新狀態,它會執行批處理作業。 因此,可能發生多個setState調用正在訪問一個參考點。 如果直接改變狀態,可能會造成混亂,因為其他狀態可以在執行批處理作業時使用更新后的狀態。

此外,如果您在 App 級別輸出 onChange 處理程序,您可以將 MetafieldInputs 更改為功能組件而不是基於類的組件。 基於功能的組件成本低於基於類的組件,並且可以提高性能。

下面是更新的代碼,經過測試。 我假設您使用 Material UI 的 TextField,但 onChangeHandler 也應該在您自己的組件中工作。

// Full App.js
import React, { Component } from 'react';
import MetafieldInputs from './MetafieldInputs';

class App extends Component {
    state = {
        metafields: [
            {
                metafield:
                {
                    namespace: "namespaceVal",
                    key: "keyVal",
                    val: [
                        { '0': "val1" },
                        { '1': "val2" },
                        { '2': "val3" }
                    ]
                }
            },
        ]
    }

    // will never be triggered as from React point of view, the state never changes
    componentDidUpdate() {
        console.log('componentDidUpdate')
    }

    render() {
        const metafields = this.state.metafields;
        const metafieldsKeys = Object.keys(metafields);
        const renderInputs = metafieldsKeys.map(key => {
            const metafield = metafields[key];
            return <MetafieldInputs metafields={metafield.metafield.val} key={metafield.metafield.key} />;
        })
        return (
            <div>
                {renderInputs}
            </div>
        )
    }
}

export default App;

// full MetafieldInputs
import React, { Component } from 'react'
import TextField from '@material-ui/core/TextField';

class MetafieldInputs extends Component {
    state = {
        metafields: this.props.metafields
    }

    onChangeHandler = (e, index) => {
        const value = e.target.value;
        this.setState(prevState => {
            const updateMetafields = [...prevState.metafields];
            const updatedFields = { ...updateMetafields[index] }
            updatedFields[index] = value
            updateMetafields[index] = updatedFields;
            return { metafields: updateMetafields }
        })
    }

    render() {
        const { metafields } = this.state;
        // will always remain the same
        console.log('this.props', this.props)
        return (
            <div>
                {metafields.map((meta, i) => {
                    return (
                        <TextField
                            value={meta[i]}
                            changekey={meta}
                            onChange={(e) => this.onChangeHandler(e, i)}
                            // generally it is not a good idea to use index as a key.
                            key={i}
                        />
                    )
                }
                )}
            </div>
        )
    }
}

export default MetafieldInputs

同樣,如果您將onChangeHandler源出到App類, MetafieldInputs可以是一個純功能組件,並且所有狀態管理都可以在App類中完成。

另一方面,如果你想保持一個純粹和干凈的App類,你也可以將元字段存儲到 MetafieldInputs 類中,以防你的應用程序中可能需要一些其他邏輯。

例如,您的應用程序渲染的組件比示例多,並且在發生某些事情之前不應渲染 MetafieldInputs。 如果從服務端取數據,最好在需要的時候取數據,而不是取App組件中的所有數據。

暫無
暫無

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

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