Существует несколько способов взаимодействия компонентов. Некоторые из них могут подойти для вашего использования. Вот список некоторых, которые я нашел полезным знать.
реагировать
Прямое общение родителей и детей
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
Здесь дочерний компонент будет вызывать обратный вызов, предоставленный родителем со значением, и родитель сможет получить значение, предоставленное дочерними элементами в родительском элементе.
Если вы создаете функцию / страницу своего приложения, лучше иметь одного родителя, управляющего обратными вызовами / состоянием (также называемого container
или smart component
), и все дочерние элементы должны быть без состояний, только сообщая обо всем родителю. Таким образом, вы можете легко «поделиться» состоянием родителя с любым ребенком, которому это нужно.
контекст
React Context позволяет хранить состояние в корне иерархии компонентов и иметь возможность легко внедрять это состояние в очень глубоко вложенные компоненты без необходимости передавать реквизиты каждому промежуточному компоненту.
До сих пор контекст был экспериментальной функцией, но в React 16.3 доступен новый API.
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
Потребитель использует шаблон функции render prop / children
Проверьте этот блог для более подробной информации.
Перед React 16.3 я бы рекомендовал использовать реакцию-трансляцию, которая предлагает довольно похожий API, и использовать прежний контекстный API.
Порталы
Используйте портал, когда вы хотите, чтобы два компонента были расположены близко друг к другу, чтобы заставить их взаимодействовать с простыми функциями, как в обычном родительском / дочернем элементе, но вы не хотите, чтобы эти два компонента имели отношения родительский / дочерний в DOM, потому что из видимых / CSS ограничений, которые это подразумевает (например, z-index, opacity ...).
В этом случае вы можете использовать «портал». Существуют разные библиотеки реагирования, использующие порталы , обычно используемые для модальных окон, всплывающих окон, всплывающих подсказок ...
Учтите следующее:
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
Может создать следующий DOM при визуализации внутри reactAppContainer
:
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
Подробнее здесь
игровые автоматы
Вы определяете слот где-то, а затем заполняете слот из другого места вашего дерева визуализации
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
Это немного похоже на порталы, за исключением того, что заполненное содержимое будет отображаться в определенном вами слоте, в то время как порталы обычно визуализируют новый узел dom (часто дочерний элемент document.body)
Проверьте библиотеку response-slot-fill
Шина событий
Как указано в документации React :
Для связи между двумя компонентами, которые не имеют отношения родитель-потомок, вы можете настроить собственную глобальную систему событий. Подписаться на события в componentDidMount (), отписаться в componentWillUnmount () и вызвать setState () при получении события.
Есть много вещей, которые вы можете использовать для настройки шины событий. Вы можете просто создать массив слушателей, и при публикации события все слушатели получат событие. Или вы можете использовать что - то вроде EventEmitter или PostalJs
Flux
Flux - это, по сути, шина событий, за исключением того, что получатели событий являются магазинами. Это похоже на базовую систему шины событий, за исключением того, что состояние управляется вне React
Оригинальная реализация Flux выглядит как попытка хакерской работы с источником событий.
Redux для меня - это реализация Flux, наиболее близкая к источникам событий, которая обладает многими преимуществами источников событий, такими как возможность путешествовать во времени. Он не связан строго с React и может также использоваться с другими библиотеками функциональных представлений.
Видео-учебник Egghead Redux действительно хорош и объясняет, как он работает внутри (это действительно просто).
курсоры
Курсоры взяты из ClojureScript / Om и широко используются в проектах React. Они позволяют управлять состоянием вне React, и позволяют нескольким компонентам иметь доступ на чтение / запись к одной и той же части состояния без необходимости что-либо знать о дереве компонентов.
Существует множество реализаций, в том числе ImmutableJS , React-курсоры и Omniscient
Edit 2016 : кажется, что люди соглашаются, что курсоры работают хорошо для небольших приложений, но это плохо масштабируется в сложных приложениях. Om Next больше не имеет курсоров (хотя Om изначально ввел эту концепцию)
Архитектура вяза
Архитектура вяза - это архитектура, предложенная для языка вяза . Даже если Elm не ReactJS, архитектура Elm также может быть реализована в React.
Дэн Абрамов, автор Redux, реализовал архитектуру Elm с использованием React.
И Redux, и Elm действительно великолепны и имеют тенденцию расширять возможности поиска событий на внешнем интерфейсе, позволяя отлаживать путешествия во времени, отменять / возвращать, воспроизводить ...
Основное различие между Redux и Elm состоит в том, что Elm, как правило, более строг в управлении государством. В Elm вы не можете иметь локальное состояние компонента или перехватывать / демонтировать хуки, и все изменения DOM должны быть вызваны глобальными изменениями состояния. Архитектура Elm предлагает масштабируемый подход, который позволяет обрабатывать ВСЕ состояние внутри одного неизменного объекта, в то время как Redux предлагает подход, который предлагает вам обрабатывать МОСТ состояния в одном неизменном объекте.
Несмотря на то, что концептуальная модель Elm очень элегантна, а архитектура позволяет хорошо масштабироваться для больших приложений, на практике это может быть затруднено или потребовать дополнительных шаблонов для решения простых задач, таких как выделение фокуса для ввода после его монтирования или интеграция с существующей библиотекой. с императивным интерфейсом (например, плагин JQuery). Связанная проблема .
Кроме того, архитектура Elm включает в себя больше кода кода. Это не настолько многословно или сложно писать, но я думаю, что архитектура Elm больше подходит для языков со статической типизацией.
FRP
Такие библиотеки, как RxJS, BaconJS или Kefir, могут использоваться для создания потоков FRP для обработки связи между компонентами.
Вы можете попробовать, например, Rx-React
Я думаю, что использование этих библиотек очень похоже на использование языка ELM с сигналами .
Платформа CycleJS не использует ReactJS, но использует vdom . Он имеет много общего с архитектурой Elm (но его проще использовать в реальной жизни, поскольку он позволяет использовать VDOM-хуки), и он широко использует RxJ вместо функций и может стать хорошим источником вдохновения, если вы хотите использовать FRP с React. CycleJs Egghead видео приятно понять, как это работает.
СНТ
CSP (передача последовательных процессов) в настоящее время популярны (в основном из-за Go / goroutines и core.async / ClojureScript), но вы можете использовать их также в javascript с JS-CSP .
Джеймс Лонг снял видео, объясняющее, как его можно использовать с React.
Саги
Сага - это бэкэнд-концепция из мира DDD / EventSourcing / CQRS, также называемая «диспетчер процессов». Он популяризируется проектом redux-saga , в основном в качестве замены для redux-thunk для обработки побочных эффектов (например, вызовов API и т. Д.). Большинство людей в настоящее время думают, что это только услуги для побочных эффектов, но на самом деле это больше касается разъединения компонентов.
Это скорее комплимент для архитектуры Flux (или Redux), чем для совершенно новой системы связи, потому что сага в конце выдает действия Flux. Идея состоит в том, что если у вас есть widget1 и widget2, и вы хотите, чтобы они были развязаны, вы не можете запустить действие таргетинга widget2 из widget1. Таким образом, вы делаете widget1 только действия, которые нацелены на себя, и сага является «фоновым процессом», который прослушивает действия widget1 и может отправлять действия, которые нацелены на widget2. Сага - это точка соединения между двумя виджетами, но виджеты остаются разъединенными.
Если вам интересно, посмотрите мой ответ здесь
Вывод
Если вы хотите увидеть пример того же маленького приложения, использующего эти разные стили, проверьте ветки этого хранилища .
Я не знаю, какой вариант лучше в долгосрочной перспективе, но мне действительно нравится, как Flux выглядит как источник событий.
Если вы не знакомы с концепциями источников событий, взгляните на этот очень педагогический блог: выверните базу данных с помощью Apache Samza , это необходимо прочитать, чтобы понять, почему Flux хорош (но это может относиться и к FRP). )
Я думаю, что сообщество соглашается с тем, что наиболее многообещающей реализацией Flux является Redux , которая будет постепенно обеспечивать очень продуктивный опыт разработчиков благодаря горячей перезагрузке. Впечатляющее живое кодирование аля видео « Изобретая по принципу» Брета Виктора, возможно!