обработка реквизитов в деконструированном дочернем элементе

#reactjs #react-props

#reactjs #react-props

Вопрос:

У меня есть компонент React, который клонирует своих дочерних элементов с помощью дополнительных реквизитов. Я использую стандартный метод childrenWithProps, который отлично работает, если ваш дочерний элемент является другим компонентом react, но нет четкого способа сделать это без прямого компонента react в качестве дочернего элемента.

 <DataCmp>
   <Fragment>
      <h1>Example Code</h1>
      <div>{isLoggedIn}</div>
   </Fragment>
</DataCmp>
 

В этом примере я добавляю реквизит myData к реквизитам его дочерних элементов. Однако это не работает. Дочерний элемент не видит значения. Он скажет, что myData не задан, когда он передается с помощью props .

Итак, я попытался это:

 <DataCmp>
   <Fragment>
      <h1>Example Code</h1>
      <div>{this.props.isLoggedIn}</div>
   </Fragment>
</DataCmp>
 

Это приводит к ошибкам, поскольку он понятия не имеет, что this.props.myData это такое.

Моей следующей попыткой было обернуть дочерний элемент во встроенную функцию и получить из него реквизит.

 <DataCmp>
  {({ isLoggedIn}) => (
   <Fragment>
      <h1>Example Code</h1>
      <div>{isLoggedIn}</div>
   </Fragment>
  )}
</DataCmp>
 

Хотя это не вызывает никаких ошибок; Дочерний компонент никогда не отображается.

Я работаю над обновлением и модернизацией чужого старого проекта Github. вот ссылка на мой проект, а завершающий компонент — Wallet.jsx.местоположение, в котором он используется, — index.jsx

Дочерние элементы отображаются как таковые:

 renderChildren = () => {
        const { children } = this.props;
        const { accounts } = this.state;
        const handleLogin = () => this.login();
        const childrenWithProps = React.Children.map(children, (child, index) => {
            if(typeof child == 'object') {
                return React.cloneElement(child, {
                    key: index,
                    loginFn: () => handleLogin(),
                    isLoggedIn: accounts[0] !== '0x0',
                    accounts,
                });
            } else {
                return child;
            }   
        });
        return childrenWithProps;
    } 
 

Комментарии:

1. Теоретически третий вариант правильный. Если дочерний элемент не отображается, возникает проблема с вашим DataCmp. Можете ли вы поделиться кодом?

2. Я обновил вопрос, включив ссылки на репозиторий Github, над которым я работаю. Я пытаюсь создать обновленную реконструкцию чужого проекта 3-летней давности.

3. Понятно, спасибо! Проблема связана с вашим использованием React.Children.map , которое выполняет итерацию только по значениям, которые квалифицируются как действительный элемент react . Вы можете проверить это с React.isValidElement(el) помощью . Я опубликую ответ

Ответ №1:

Я предполагаю, что ошибка может быть не в деструктурировании, а в том, как вы его используете childrenWithProps .

Было бы полезно, если бы вы поделились condesandbox, представляющим проблему с фиктивными данными, чтобы мы могли взглянуть и на эту часть.

Комментарии:

1. Я включил ссылки на мой GitHub, где находится исходный код.

Ответ №2:

React.Children.map(children, fn) выполняет итерацию только по допустимым элементам react

Это исключает, например, функции, передаваемые как дочерние. Передача функции, подлежащей рендерингу в качестве реквизита, компоненту называется шаблоном рендеринга реквизита. Реагируйте.Children.map не будет повторять это, следовательно, ваш третий вариант будет возвращен null .

Исправьте это, сначала проверив, является ли children ReactElement допустимым, и отобразите его соответствующим образом:

 
// wallet.tsx
...
const additionalProps = { ... };
if (React.isValidElement(children)) {
  return React.Children.map(children,
    (child, i) => React.cloneElement(child, { key: i, ...additionalProps });
} else {
  // handle null, strings, undefined, booleans etc
  return typeof children === 'function' ? children(additionalProps) : children;
}
...

// index.tsx

<Wallet ...>
  {/* either a function */}
  {(additionalProps) => console.log(additionalProps)}

  {/* or components */}
  <Layout>
    ...
  </Layout>
</Wallet>
 

Обратите внимание, что это React.isValidElement() также возвращает true для HTML-элементов. Который получит реквизит, но вы, очевидно, не можете добавить пользовательскую логику. Но допустим, вы передаете style реквизит, он будет применен.