Skip to content

Commit

Permalink
Use amp-context notify to sync with Resource
Browse files Browse the repository at this point in the history
  • Loading branch information
jridgewell committed Dec 10, 2019
1 parent 16281d3 commit 22ed27f
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 13 deletions.
2 changes: 1 addition & 1 deletion examples/amp-date-display.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<h1>Date & time</h1>
<div class="meta">
<h2>Available variables</h2>
<amp-date-display datetime="2017-08-02T20:05:05.000Z" display-in="utc" layout="fixed" width="360" height="140" >
<amp-date-display datetime="2017-08-02T20:05:05.000Z" display-in="utc" layout="container" width="360" height="140" >
<template type="amp-mustache">
<div>iso: {{iso}}</div>
<div>day: {{day}} {{dayTwoDigit}} {{dayName}} {{dayNameShort}}</div>
Expand Down
16 changes: 12 additions & 4 deletions extensions/amp-date-display/0.2/amp-date-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@
import {AmpEvents} from '../../../src/amp-events';
import {PreactBaseElement} from '../../../src/preact-base-element';
import {Services} from '../../../src/services';
import {cloneElement, createElement} from 'preact';
import {createCustomEvent} from '../../../src/event-helper';
import {createElement} from 'preact';
import {dev, userAssert} from '../../../src/log';
import {isLayoutSizeDefined} from '../../../src/layout';
import {removeChildren, rootNodeFor} from '../../../src/dom';
import {useLayoutEffect, useRef} from 'preact/hooks';
import {
useMountLayoutEffect,
useRerenderer,
useResourcesNotify,
} from '../../../src/preact/utils';
import {useRef} from 'preact/hooks';

/** @const {string} */
const TAG = 'amp-date-display';
Expand Down Expand Up @@ -222,11 +227,13 @@ function getVariablesInUTC(date, locale) {
* @return {*} TODO
*/
function AmpDateDisplayComponent(props) {
useResourcesNotify();
const ref = useRef();
const data = /** @type {!JsonObject} */ (getDataForTemplate(props));
const {templates} = props.services;
const rerender = useRerenderer();

useLayoutEffect(() => {
useMountLayoutEffect(() => {
const {host} = rootNodeFor(ref.current);
templates.findAndRenderTemplate(host, data).then(rendered => {
const win = host.ownerDocument.defaultView;
Expand All @@ -242,8 +249,9 @@ function AmpDateDisplayComponent(props) {
{bubbles: true}
);
host.dispatchEvent(event);
rerender();
});
}, []);
});
return createElement('div', {ref}, props['children']);
}

Expand Down
3 changes: 2 additions & 1 deletion src/preact-base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function PreactBaseElement(Component, opts = {}) {
this.context_ = {
renderable: false,
playable: false,
notify: () => this.mutateElement(() => {}),
};

this.boundRerender_ = () => {
Expand Down Expand Up @@ -302,7 +303,7 @@ function getContextFromDom(node, context) {
while (n) {
const nodeContext = n['i-amphtml-context'];
if (nodeContext) {
Object.assign({}, context, nodeContext);
return Object.assign({}, nodeContext, context);
break;
}
n = n.assignedSlot || n.parentNode || n.host;
Expand Down
13 changes: 7 additions & 6 deletions src/preact/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ export function getAmpContext() {
*/
export function withAmpContext(props) {
const parent = useContext(getAmpContext());
const current = {
const current = Object.assign({}, props, {
renderable: parent.renderable && props.renderable,
playable: parent.playable && props.playable,
};
children: undefined,
});

return createElement(
getAmpContext().Provider,
Object.assign({}, props, {value: current})
);
return createElement(getAmpContext().Provider, {
children: props.children,
value: current,
});
}
52 changes: 51 additions & 1 deletion src/preact/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
* limitations under the License.
*/

import {useEffect} from 'preact/hooks';
import {getAmpContext} from './context';
import {
useContext,
useEffect,
useLayoutEffect,
useRef,
useState,
} from 'preact/hooks';

/**
* @param {function} callback
Expand All @@ -24,3 +31,46 @@ export function useMountEffect(callback) {
/* mount-only effect*/
]);
}

/**
* @param {function} callback
*/
export function useMountLayoutEffect(callback) {
useLayoutEffect(callback, [
/* mount-only effect*/
]);
}

/**
* Notifies Resources (if present) of a rerender in the component.
* Every functional component **must** use this helper.
*/
export function useResourcesNotify() {
const ctx = useContext(getAmpContext());
const notify = ctx && ctx.notify;
useLayoutEffect(() => {
if (notify) {
notify();
}
});
}

/**
* @param {number} current
* @return {number}
*/
function increment(current) {
return current + 1;
}

/**
* @return {function()}
*/
export function useRerenderer() {
const state = useState(0);
// We only care about the setter, which is the second item of the tuple.
const set = state[1];
// useRef ensures the callback's instance identity is consistent.
const ref = useRef(() => set(increment));
return ref.current;
}

0 comments on commit 22ed27f

Please sign in to comment.