# create-subscription
`create-subscription` is a utility for subscribing to external data sources inside React components. It is officially supported and maintained by the React team.
## When should you NOT use this?
This utility should be used for subscriptions to a single value that are typically only read in one place and may update frequently (e.g. a component that subscribes to a geolocation API to show a dot on a map).
Other cases have **better long-term solutions**:
* Redux/Flux stores should use the [context API](https://reactjs.org/docs/context.html) instead.
* I/O subscriptions (e.g. notifications) that update infrequently should use [`react-cache`](https://github.com/facebook/react/blob/master/packages/react-cache/README.md) instead.
* Complex libraries like Relay/Apollo should manage subscriptions manually with the same techniques which this library uses under the hood (as referenced [here](https://gist.github.com/bvaughn/d569177d70b50b58bff69c3c4a5353f3)) in a way that is most optimized for their library usage.
## Limitations in async mode
The main motivation for `create-subscription` is to provide a way for library authors to ensure compatibility with React's upcoming asynchronous rendering mode. `create-subscription` guarantees correctness in async mode, accounting for the subtle bugs and edge cases that a library author might otherwise miss.
However, [it achieves correctness by sometimes de-opting to synchronous mode](https://github.com/facebook/react/issues/13186#issuecomment-403959161), obviating the benefits of async rendering. This is an inherent limitation of storing state outside of React's managed state queue and rendering in response to a change event.
The effect of de-opting to sync mode is that the main thread may periodically be blocked (in the case of CPU-bound work), and placeholders may appear earlier than desired (in the case of IO-bound work).
For **full compatibility** with asynchronous rendering, including both **time-slicing** and **React Suspense**, the suggested longer-term solution is to move to one of the patterns described in the previous section.
## What types of subscriptions can this support?
This abstraction can handle a variety of subscription types, including:
* Event dispatchers like `HTMLInputElement`.
* Custom pub/sub components like Relay's `FragmentSpecResolver`.
* Observable types like RxJS `BehaviorSubject` and `ReplaySubject`. (Types like RxJS `Subject` or `Observable` are not supported, because they provide no way to read the "current" value after it has been emitted.)
* Native Promises.
# Installation
```sh
# Yarn
yarn add create-subscription
# NPM
npm install create-subscription
```
# Usage
To configure a subscription, you must provide two methods: `getCurrentValue` and `subscribe`.
```js
import { createSubscription } from "create-subscription";
const Subscription = createSubscription({
getCurrentValue(source) {
// Return the current value of the subscription (source),
// or `undefined` if the value can't be read synchronously (e.g. native Promises).
},
subscribe(source, callback) {
// Subscribe (e.g. add an event listener) to the subscription (source).
// Call callback(newValue) whenever a subscription changes.
// Return an unsubscribe method,
// Or a no-op if unsubscribe is not supported (e.g. native Promises).
}
});
```
To use the `Subscription` component, pass the subscribable property (e.g. an event dispatcher, observable) as the `source` property and use a [render prop](https://reactjs.org/docs/render-props.html), `children`, to handle the subscribed value when it changes:
```js
<Subscription source={eventDispatcher}>
{value => <AnotherComponent value={value} />}
</Subscription>
```
# Examples
This API can be used to subscribe to a variety of "subscribable" sources, from event dispatchers to RxJS observables. Below are a few examples of how to subscribe to common types.
## Subscribing to event dispatchers
Below is an example showing how `create-subscription` can be used to subscribe to event dispatchers such as DOM elements.
```js
import React from "react";
import { createSubscription } from "create-subscription";
// Start with a simple component.
// In this case, it's a function component, but it could have been a class.
function FollowerComponent({ followersCount }) {
return <div>You have {followersCount} followers!</div>;
}
// Create a wrapper component to manage the subscription.
const EventHandlerSubscription = createSubscription({
getCurrentValue: eventDispatcher => eventDispatcher.value,
subscribe: (eventDispatcher, callback) => {
const onChange = event => callback(eventDispatcher.value);
eventDispatcher.addEventListener("change", onChange);
return () => eventDispatcher.removeEventListener("change", onChange);
}
});
// Your component can now be used as shown below.
// In this example, 'eventDispatcher' represents a generic event dispatcher.
<EventHandlerSubscription source={eventDispatcher}>
{value => <FollowerComponent followersCount={value} />}
</EventHandlerSubscription>;
```
## Subscribing to observables
Below are examples showing how `create-subscription` can be used to subscribe to certain types of observables (e.g. RxJS `BehaviorSubject` and `ReplaySubject`).
**Note** that it is not possible to support all observable types (e.g. RxJS `Subject` or `Observable`) because some provide no way to read the "current" value after it has been emitted.
### `BehaviorSubject`
```js
const BehaviorSubscription = createSubscription({
getCurrentValue: behaviorSubject => behaviorSubject.getValue(),
subscribe: (behaviorSubject, callback) => {
const subscription = behaviorSubject.subscribe(callback);
return () => subscription.unsubscribe();
}
});
```
### `ReplaySubject`
```js
const ReplaySubscription = createSubscription({
getCurrentValue: replaySubject => {
let currentValue;
// ReplaySubject does not have a sync data getter,
// So we need to temporarily subscribe to retrieve the most recent value.
replaySubject
.subscribe(value => {
currentValue = value;
})
.unsubscribe();
return currentValue;
},
subscribe: (replaySubject, callback) => {
const subscription = replaySubject.subscribe(callback);
return () => subscription.unsubscribe();
}
});
```
## Subscribing to a Promise
Below is an example showing how `create-subscription` can be used with native Promises.
**Note** that an initial render value of `undefined` is unavoidable due to the fact that Promises provide no way to synchronously read their current value.
**Note** the lack of a way to "unsubscribe" from a Promise can result in memory leaks as long as something has a reference to the Promise. This should be taken into consideration when determining whether Promises are appropriate to use in this way within your application.
```js
import React from "react";
import { createSubscription } from "create-subscription";
// Start with a simple component.
function LoadingComponent({ loadingStatus }) {
if (loadingStatus === undefined) {
// Loading
} else if (loadingStatus === null) {
// Error
} else {
// Success
}
}
// Wrap the function component with a subscriber HOC.
// This HOC will manage subscriptions and pass values to the decorated component.
// It will add and remove subscriptions in an async-safe way when props change.
const PromiseSubscription = createSubscription({
getCurrentValue: promise => {
// There is no way to synchronously read a Promise's value,
// So this method should return undefined.
return undefined;
},
subscribe: (promise, callback) => {
promise.then(
// Success
value => callback(value),
// Failure
() => callback(null)
);
// There is no way to "unsubscribe" from a Promise.
// create-subscription will still prevent stale values from rendering.
return () => {};
}
});
// You
没有合适的资源?快使用搜索试试~ 我知道了~
react-16.8.2.tar.gz
需积分: 0 0 下载量 38 浏览量
2024-05-04
14:36:11
上传
评论
收藏 3.72MB GZ 举报
温馨提示
共1075个文件
js:817个
json:51个
html:39个
react.js for linux 各个版本,免费下载 前端三大框架之一 react 各个版本,免费下载 如果下载不了,关注我,评论区联系我 React 是一个库。它允许你将组件放在一起,但不关注路由和数据获取。要使用 React 构建整个应用程序,建议使用像 Next.js 或 Remix 这样的全栈 React 框架。
资源推荐
资源详情
资源评论
收起资源包目录
react-16.8.2.tar.gz (1075个子文件)
AUTHORS 42KB
authors 284B
.babelrc 835B
ReactCoffeeScriptClass-test.coffee 16KB
hardware-counter.cpp 12KB
jsc-perf.cpp 5KB
thread-local.cpp 2KB
perf-counters.cpp 1KB
style.css 4KB
codemirror-paraiso-dark.css 2KB
index.css 2KB
index.css 2KB
Spinner.css 1KB
hydration.css 1KB
style.css 918B
Chrome.css 394B
Page.css 243B
index.css 189B
index.css 87B
App.css 1B
.editorconfig 293B
.env 30B
.eslintignore 211B
eslintignore 211B
flowconfig 1KB
grayarrow.gif 111B
.gitattributes 12B
.gitignore 403B
.gitignore 395B
.gitignore 345B
.gitignore 334B
.gitignore 285B
.gitignore 175B
.gitignore 174B
.gitignore 52B
.gitignore 23B
.gitignore 23B
.gitignore 19B
.gitignore 10B
.gitignore 10B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
.gitignore 9B
binding.gyp 259B
thread-local.h 19KB
portability.h 5KB
hardware-counter.h 3KB
index.html 18KB
index.html 7KB
index.html 3KB
index.html 3KB
index.html 2KB
renderer.html 2KB
index.html 2KB
index.html 2KB
index.html 1KB
index.html 1KB
index.html 1KB
index.html 946B
index.html 946B
index.html 946B
test.html 760B
prod.html 739B
dev.html 733B
prod.html 616B
dev.html 610B
index.html 482B
dev.html 473B
prod.html 413B
dev.html 407B
index.html 401B
index.html 385B
index.html 326B
index.html 283B
index.html 175B
index.html 175B
index.html 146B
index.html 146B
index.html 102B
index.html 102B
index.html 102B
index.html 102B
index.html 102B
index.html 102B
index.html 102B
index.html 102B
favicon.ico 24KB
favicon.ico 24KB
favicon.ico 24KB
favicon.ico 24KB
favicon.ico 24KB
favicon.ico 4KB
gaearon.jpeg 41KB
flarnie.jpeg 32KB
共 1075 条
- 1
- 2
- 3
- 4
- 5
- 6
- 11
资源评论
段子手-168
- 粉丝: 1830
- 资源: 2266
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功