#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
реквизит, он будет применен.