繁体   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