Передача данных через вложенные компоненты в React - PullRequest
3 голосов
/ 05 февраля 2020

Предусматривая это с мыслью; Я думаю, что мне может потребоваться рекурсивный компонент, но это выходит за рамки моих нынешних способностей с нативными js и React, поэтому я чувствую, что у меня уже есть понимание React со швейцарским сыром.

Проблема :

У меня есть массив metafields, содержащий metafield объектов со следующей структурой:

{
  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.

руководство будет высоко ценится!

Ответы [ 2 ]

0 голосов
/ 05 февраля 2020

Мое предложение состоит в том, чтобы исходить из обработчика onChange, и код можно понять немного проще.

В основном React не обновляет состояние сразу после вызова setState(), он выполняет пакет работа. Поэтому может случиться так, что несколько вызовов setState обращаются к одной контрольной точке. Если вы напрямую изменяете состояние, это может вызвать хаос, так как другое состояние может использовать обновленное состояние при выполнении пакетного задания.

Кроме того, если вы обработали обработчик source onChange на уровне приложения, вы можете изменить MetafieldInputs на функциональный компонент, а не компонент баз классов. Функциональный компонент стоит меньше, чем компонентный класс, и может повысить производительность.

Ниже приведен проверенный обновленный код. Я предполагаю, что вы используете 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. Класс в случае, если вам может понадобиться другой лог c в вашем приложении.

Например, ваше приложение отображает больше компонентов, чем в примере, и MetafieldInputs не следует отображать, пока что-то не произойдет. Если вы извлекаете данные со стороны сервера, лучше извлекать данные, когда они необходимы, а не извлекать все данные в компоненте приложения.

0 голосов
/ 05 февраля 2020

Вам нужно сделать onChange на уровне приложения. Вы должны просто передать функцию onChange в MetaFieldsInput и всегда использовать this.props.metafields при рендеринге

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...