Skip to content

Commit

Permalink
Merge pull request #74 from codesandbox/danilo/csb-571-listener-is-mi…
Browse files Browse the repository at this point in the history
…ssing-to-registeremit

Listener is missing to register emit
  • Loading branch information
danilowoz authored Jul 6, 2021
2 parents 1f16534 + 6b69b50 commit 9206733
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 18 deletions.
18 changes: 10 additions & 8 deletions sandpack-client/gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { task, src, dest } from "gulp";
const gulp = require("gulp");

task("copy-sandbox", () =>
src([
"../../codesandbox-client/www/**/*.*",
"!../../codesandbox-client/www/**/*.map",
"!../../codesandbox-client/www/stats.json",
"!../../codesandbox-client/www/public/**/*.*",
]).pipe(dest("./sandpack/"))
gulp.task("copy-sandbox", () =>
gulp
.src([
"../../codesandbox-client/www/**/*.*",
"!../../codesandbox-client/www/**/*.map",
"!../../codesandbox-client/www/stats.json",
"!../../codesandbox-client/www/public/**/*.*",
])
.pipe(gulp.dest("./sandpack/"))
);
2 changes: 1 addition & 1 deletion sandpack-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codesandbox/sandpack-client",
"version": "0.1.0",
"version": "0.1.2",
"description": "",
"keywords": [],
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions sandpack-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codesandbox/sandpack-react",
"version": "0.1.0",
"version": "0.1.2",
"description": "",
"keywords": [],
"repository": {
Expand Down Expand Up @@ -43,7 +43,7 @@
"@codemirror/matchbrackets": "^0.18.0",
"@codemirror/state": "^0.18.0",
"@codemirror/view": "^0.18.0",
"@codesandbox/sandpack-client": "^0.1.0",
"@codesandbox/sandpack-client": "^0.1.2",
"codesandbox-import-utils": "^2.2.3",
"codesandbox-import-util-types": "^2.2.3",
"prism-react-renderer": "^1.1.1"
Expand Down
70 changes: 63 additions & 7 deletions sandpack-react/src/contexts/sandpackContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,18 @@ class SandpackProvider extends React.PureComponent<
renderHiddenIframe: false,
};

this.queuedListeners = {};
/**
* List of functions to be registered in the client, once it has been created
*
* Use cases:
* - Set a listener, but the client hasn't been created yet;
* - Set a listener, but the client has already been created;
* - A client already exists, set a new listener and then one more client has been created;
*/
this.queuedListeners = { global: {} };
/**
* Global list of unsubscribe function for the listeners
*/
this.unsubscribeQueuedListeners = {};
this.preregisteredIframes = {};
this.clients = {};
Expand Down Expand Up @@ -301,8 +312,10 @@ class SandpackProvider extends React.PureComponent<
}, BUNDLER_TIMEOUT);
}

/**
* Register any potential listeners that subscribed before sandpack ran
*/
if (this.queuedListeners[clientId]) {
// Register any potential listeners that subscribed before sandpack ran
Object.keys(this.queuedListeners[clientId]).forEach((listenerId) => {
const listener = this.queuedListeners[clientId][listenerId];
const unsubscribe = client.listen(listener) as () => void;
Expand All @@ -313,6 +326,21 @@ class SandpackProvider extends React.PureComponent<
this.queuedListeners[clientId] = {};
}

/**
* Register global listeners
*/
const globalListeners = Object.entries(this.queuedListeners.global);
globalListeners.forEach(([listenerId, listener]) => {
const unsubscribe = client.listen(listener) as () => void;
this.unsubscribeQueuedListeners[clientId][listenerId] = unsubscribe;

/**
* Important: Do not clean the global queue
* Instead of cleaning the queue, keep it there for the
* following clients that might be created
*/
});

return client;
};

Expand All @@ -338,7 +366,6 @@ class SandpackProvider extends React.PureComponent<
if (client) {
client.cleanup();
delete this.clients[clientId];
delete this.unsubscribeQueuedListeners[clientId];
} else {
delete this.preregisteredIframes[clientId];
}
Expand Down Expand Up @@ -383,7 +410,9 @@ class SandpackProvider extends React.PureComponent<
): UnsubscribeFunction => {
if (clientId) {
if (this.clients[clientId]) {
return this.clients[clientId].listen(listener);
const unsubscribeListener = this.clients[clientId].listen(listener);

return unsubscribeListener;
} else {
// When listeners are added before the client is instantiated, they are stored with an unique id
// When the client is eventually instantiated, the listeners are registered on the spot
Expand All @@ -394,7 +423,8 @@ class SandpackProvider extends React.PureComponent<
this.unsubscribeQueuedListeners[clientId] || {};

this.queuedListeners[clientId][listenerId] = listener;
return () => {

const unsubscribeListener = () => {
if (this.queuedListeners[clientId][listenerId]) {
// unsubscribe was called before the client was instantiated
// common example - a component with autorun=false that unmounted
Expand All @@ -406,12 +436,38 @@ class SandpackProvider extends React.PureComponent<
delete this.unsubscribeQueuedListeners[clientId][listenerId];
}
};

return unsubscribeListener;
}
} else {
const unsubs = Object.values(this.clients).map((client) =>
// Push to the **global** queue
const listenerId = generateRandomId();
this.queuedListeners.global[listenerId] = listener;

// Add to the current clients
const clients = Object.values(this.clients);
const currentClientUnsubscribeListeners = clients.map((client) =>
client.listen(listener)
);
return () => unsubs.forEach((unsub) => unsub());

const unsubscribeListener = () => {
const unsubscribeQueuedClients = Object.values(
this.unsubscribeQueuedListeners
);

// Unsubscribing all listener registered
unsubscribeQueuedClients.forEach((listenerOfClient) => {
const listenerFunctions = Object.values(listenerOfClient);
listenerFunctions.forEach((unsubscribe) => unsubscribe());
});

// Unsubscribing from the clients already created
currentClientUnsubscribeListeners.forEach((unsubscribe) =>
unsubscribe()
);
};

return unsubscribeListener;
}
};

Expand Down
45 changes: 45 additions & 0 deletions sandpack-react/src/presets/CustomSandpack.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,51 @@ export const MultiplePreviews: React.FC = () => {
);
};

function SandpackListener() {
const { listen } = useSandpack();

useEffect(() => {
const unsubscribe = listen((msg) => console.log(msg));

return unsubscribe;
}, [listen]);

return null;
}

export const MultiplePreviewsAndListeners: React.FC = () => {
const [count, setCount] = useState(2);
const [listenersCount, setListenersCount] = useState(0);

const previews = Array.from(Array(count).keys());

return (
<>
<SandpackProvider template="react">
{new Array(listenersCount).fill(" ").map((pr) => (
<SandpackListener key={pr} />
))}
<SandpackLayout>
<SandpackCodeEditor />
{previews.map((pr) => (
<SandpackPreview key={pr} />
))}
</SandpackLayout>
</SandpackProvider>
<button onClick={() => setCount(count + 1)}>Add</button>
<button onClick={() => setCount(count - 1)}>Remove</button>

<p>Amount of listeners: {listenersCount}</p>
<button onClick={() => setListenersCount(listenersCount + 1)}>
Add listener
</button>
<button onClick={() => setListenersCount(listenersCount - 1)}>
Remove listener
</button>
</>
);
};

const Box: React.FC<{
label?: string;
width?: number | string;
Expand Down

0 comments on commit 9206733

Please sign in to comment.