React: Клонирование дочернего элемента контекста Consumer приводит к появлению сбивающих с толку предупреждений и ошибок.

Созданный на 25 апр. 2018  ·  4Комментарии  ·  Источник: facebook/react

Вы хотите запросить функцию или сообщить об ошибке ?
это ошибка или, по крайней мере, запрос на более точные предупреждения и сообщения об ошибках.

Каково текущее поведение?

Я клонировал детей, чтобы добавить некоторые свойства, и я упустил из виду, что контекстное поддерево Consumer не должно клонироваться ...

import React from 'react';
import {render} from 'react-dom';

const { Provider, Consumer} = React.createContext();

const Comp = ({children})=> <Provider>{cloneKids(children)}</Provider>;

const cloneKids=(children)=>React.Children.map(children, child =>
                           React.cloneElement(child, child.props,
                                  child.props.children&&
                                  cloneKids(child.props.children)));
render(
    <Comp><Consumer>{console.log}</Consumer></Comp>,
    document.getElementById('root')
);

Код выдает предупреждение и ошибку, введенную с # 12241.

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

и (что еще более запутанно)

TypeError: рендеринг не является функцией

Какое поведение ожидается?

Может быть, React.cloneElement не должен пытаться клонировать функции? Что бы он ни делал, результат - это не функция.

Часть предупреждения «дочерний элемент, который не является функцией» следует отделить от других предупреждений. Не может быть нескольких дочерних элементов и одного дочернего элемента, который не является функцией одновременно, поэтому может быть выдано более точное предупреждение.

Какие версии React и какой браузер / ОС подвержены этой проблеме?

Протестировано с помощью react 16.3.0 в Stackblitz / Chrome 65 и React 16.3.2 в Chrome 65 и Firefox 59.

Question

Самый полезный комментарий

Проблема не в cloneElement (у него нет специальной логики для контекста), а в том, что вы передаете props.children (который в данном случае является функцией) в Children.map() (который не ожидает функций). Children.map работает только с обычными узлами React.

Возможно, Children.map может показать предупреждение, когда обнаружит что-то, что не является узлом React.

В любом случае такое глубокое клонирование деревьев React звучит так, будто вы пытаетесь сделать что-то, для чего React не был разработан. Зачем тебе это нужно?

Все 4 Комментарий

Проблема не в cloneElement (у него нет специальной логики для контекста), а в том, что вы передаете props.children (который в данном случае является функцией) в Children.map() (который не ожидает функций). Children.map работает только с обычными узлами React.

Возможно, Children.map может показать предупреждение, когда обнаружит что-то, что не является узлом React.

В любом случае такое глубокое клонирование деревьев React звучит так, будто вы пытаетесь сделать что-то, для чего React не был разработан. Зачем тебе это нужно?

Спасибо!

Я откладываю оценку нескольких дочерних свойств до тех пор, пока родитель не будет готов предоставить контекст для их оценки. Например:

<Parent ><Child prefix-prop="string expression"></Parent>
(язык выражений - это не javascript, и он оценивается удаленно. Я не контролирую Child, и их может быть любое количество).

Ребенок внутренне становится чем-то вроде:

<Child prop={evaluate("string expression")} />

Для этого родитель посещает потомков и преобразует свойство prefix-prop, содержащее выражение, в свойство prop, которое содержит значение выражения. Клонирование - единственный подход, который я нашел для изменения свойств компонентов. Конечно, потребители контекста не должны клонироваться, там нет никаких свойств, которые нужно изменять.

Я знаю, что мне следует использовать функцию-как-потомок или функции рендеринга или аналогичные (чтобы отложить оценку), но я разрабатываю библиотеку прототипов и своих пользователей (которые пришли из HTML и JSP и часто являются новичками за пределами HTML и языка выражений) скорее всего, не оценят эту нотацию:

<Parent>{ context=> <Child prop={context.evaluate(x)} />}</Parent>

(кроме того, если они забудут пробел непосредственно перед функцией, их запутает # 12689)

и они не сразу поймут и эту форму:
<Parent display={ context=> <Child prop={context.evaluate(x)} />} />

Потребители контекста также используют функцию как потомок, поэтому у них такая же проблема.

Это очень ранняя работа, поэтому я все еще рассматриваю варианты, но я как-то хочу прийти к чистой нотации родитель-потомок, как в первой цитате. Возможно, мне стоит написать плагин babel, который преобразует "чистую" нотацию в функциональную.

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

Другая идея, с которой я играю, - это функциональный родитель, вероятно, возвращающий Component (какой-то HOC)

({context})=>
context.parent("context expression",
     context2=><Child prop={context2.evaluate("sub-expression")} context={context2} />)

где Child может снова содержать вызовы context.parent () и так далее.

Конечно, parent () может использовать Consumer контекста в render () компонента, который он возвращает, поэтому контекстную опору можно отбросить:

()=>
parent("context expression",
     context2=><Child prop={context2.evaluate("sub-expression")} />)

_ Проблема здесь в том, что parent (), являющийся Компонентом, может получить доступ к контексту React, но eval () не может (насколько мне известно) получить доступ к контексту React, если он не возвращает Component_

что невозможно, когда вы фактически пытаетесь установить свойство.

Поэтому я считаю, что доступ к контексту React из внешних компонентов был бы идеальным. Что-то типа

React.getContext(Consumer, data=> ...)

Если я правильно помню, борясь с этим, я пытался вызвать Consumer.render () вручную с помощью тестовой среды, но я не получил ничего значимого.

PS: Первое обозначение выше может показаться загадочным, но на самом деле оно хорошо знакомо с текущей формой JSP, поэтому я думаю, что могу продать его пользователям :)

<context:parent ctx="context-expression">
   HTML...<context:evaluate expr="sub-expression" />...HTML
</context:parent>

Собираюсь заканчивать, потому что это не так часто случается.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги