1 | /**
|
2 | * Copyright (c) Facebook, Inc. and its affiliates.
|
3 | *
|
4 | * This source code is licensed under the MIT license found in the
|
5 | * LICENSE file in the root directory of this source tree.
|
6 | *
|
7 | * @emails oncall+relay
|
8 | *
|
9 | * @format
|
10 | */
|
11 | ;
|
12 |
|
13 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
14 |
|
15 | var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
16 |
|
17 | var React = require('react');
|
18 |
|
19 | var useMemo = React.useMemo;
|
20 | /**
|
21 | * Renders the results of a data-driven dependency fetched with the `@match`
|
22 | * directive. The `@match` directive can be used to specify a mapping of
|
23 | * result types to the containers used to render those types. The result
|
24 | * value is an opaque object that described which component was selected
|
25 | * and a reference to its data. Use <MatchContainer/> to render these
|
26 | * values.
|
27 | *
|
28 | * ## Example
|
29 | *
|
30 | * For example, consider a piece of media content that might be text or
|
31 | * an image, where for clients that don't support images the application
|
32 | * should fall back to rendering the image caption as text. @match can be
|
33 | * used to dynamically select whether to render a given media item as
|
34 | * an image or text (on the server) and then fetch the corresponding
|
35 | * React component and its data dependencies (information about the
|
36 | * image or about the text).
|
37 | *
|
38 | * ```
|
39 | * // Media.react.js
|
40 | *
|
41 | * // Define a React component that uses <MatchContainer> to render the
|
42 | * // results of a @module selection
|
43 | * function Media(props) {
|
44 | * const {media, ...restPropsj} = props;
|
45 | *
|
46 | * const loader = moduleReference => {
|
47 | * // given the data returned by your server for the @module directive,
|
48 | * // return the React component (or throw a Suspense promise if
|
49 | * // it is loading asynchronously).
|
50 | * todo_returnModuleOrThrowPromise(moduleReference);
|
51 | * };
|
52 | * return <MatchContainer match={media.mediaAttachment} props={restProps} />;
|
53 | * }
|
54 | *
|
55 | * module.exports = createSuspenseFragmentContainer(
|
56 | * Media,
|
57 | * {
|
58 | * media: graphql`
|
59 | * fragment Media_media on Media {
|
60 | * # ...
|
61 | * mediaAttachment @match {
|
62 | * ...ImageContainer_image @module(name: "ImageContainer.react")
|
63 | * ...TextContainer_text @module(name: "TextContainer.react")
|
64 | * }
|
65 | * }
|
66 | * `
|
67 | * },
|
68 | * );
|
69 | * ```
|
70 | *
|
71 | * ## API
|
72 | *
|
73 | * MatchContainer accepts the following props:
|
74 | * - `match`: The results (an opaque object) of a `@match` field.
|
75 | * - `props`: Props that should be passed through to the dynamically
|
76 | * selected component. Note that any of the components listed in
|
77 | * `@module()` could be selected, so all components should accept
|
78 | * the value passed here.
|
79 | * - `loader`: A function to load a module given a reference (whatever
|
80 | * your server returns for the `js(moduleName: String)` field).
|
81 | *
|
82 | */
|
83 | // Note: this type is intentionally non-exact, it is expected that the
|
84 | // object may contain sibling fields.
|
85 |
|
86 | function MatchContainer(_ref2) {
|
87 | var _ref;
|
88 |
|
89 | var fallback = _ref2.fallback,
|
90 | loader = _ref2.loader,
|
91 | match = _ref2.match,
|
92 | props = _ref2.props;
|
93 |
|
94 | if (match != null && typeof match !== 'object') {
|
95 | throw new Error('MatchContainer: Expected `match` value to be an object or null/undefined.');
|
96 | } // NOTE: the MatchPointer type has a $fragmentRefs field to ensure that only
|
97 | // an object that contains a FragmentSpread can be passed. If the fragment
|
98 | // spread matches, then the metadata fields below (__id, __fragments, etc)
|
99 | // will be present. But they can be missing if all the fragment spreads use
|
100 | // @module and none of the types matched. The cast here is necessary because
|
101 | // fragment Flow types don't describe metadata fields, only the actual schema
|
102 | // fields the developer selected.
|
103 |
|
104 |
|
105 | var _ref3 = (_ref = match) !== null && _ref !== void 0 ? _ref : {},
|
106 | __id = _ref3.__id,
|
107 | __fragments = _ref3.__fragments,
|
108 | __fragmentOwner = _ref3.__fragmentOwner,
|
109 | __fragmentPropName = _ref3.__fragmentPropName,
|
110 | __module_component = _ref3.__module_component;
|
111 |
|
112 | if (__fragmentOwner != null && typeof __fragmentOwner !== 'object' || __fragmentPropName != null && typeof __fragmentPropName !== 'string' || __fragments != null && typeof __fragments !== 'object' || __id != null && typeof __id !== 'string') {
|
113 | throw new Error("MatchContainer: Invalid 'match' value, expected an object that has a " + "'...SomeFragment' spread.");
|
114 | }
|
115 |
|
116 | var LoadedContainer = __module_component != null ? loader(__module_component) : null;
|
117 | var fragmentProps = useMemo(function () {
|
118 | // TODO: Perform this transformation in RelayReader so that unchanged
|
119 | // output of subscriptions already has a stable identity.
|
120 | if (__fragmentPropName != null && __id != null && __fragments != null) {
|
121 | var fragProps = {};
|
122 | fragProps[__fragmentPropName] = {
|
123 | __id: __id,
|
124 | __fragments: __fragments,
|
125 | __fragmentOwner: __fragmentOwner
|
126 | };
|
127 | return fragProps;
|
128 | }
|
129 |
|
130 | return null;
|
131 | }, [__id, __fragments, __fragmentOwner, __fragmentPropName]);
|
132 |
|
133 | if (LoadedContainer != null && fragmentProps != null) {
|
134 | return React.createElement(LoadedContainer, (0, _extends2["default"])({}, props, fragmentProps));
|
135 | } else {
|
136 | var _fallback;
|
137 |
|
138 | return (_fallback = fallback) !== null && _fallback !== void 0 ? _fallback : null;
|
139 | }
|
140 | }
|
141 |
|
142 | module.exports = MatchContainer; |
\ | No newline at end of file |