Coder Social home page Coder Social logo

rdb / svelte-meteor-data Goto Github PK

View Code? Open in Web Editor NEW
16.0 5.0 7.0 31 KB

Reactively track Meteor data inside Svelte components

Home Page: https://atmospherejs.com/rdb/svelte-meteor-data

License: MIT License

JavaScript 100.00%
svelte svelte3 svelte-js svelte-v3 sveltejs meteor meteor-package meteorjs

svelte-meteor-data's Introduction

svelte-meteor-data

This package integrates the Svelte UI framework with Meteor's Tracker system. It makes it easy to write Svelte components which react automatically to changes in Meteor's data layer.

This package is still experimental. Use at your peril.

Installation

To add Svelte to your Meteor app, run:

meteor add svelte:compiler rdb:svelte-meteor-data
meteor npm install --save [email protected]

Usage

Unlike in Blaze, Svelte does not automatically become aware of changes to Meteor state, even inside $: blocks. This package provides some features that enable Svelte to become aware of such changes.

Reactive computations with useTracker

The useTracker() function can be used to expose any reactive computation as a Svelte store. You need only pass a callable returning a computed value, which will be run the first time it is used and then every time the computed value changes. The updated value is automatically made available to Svelte.

For example, this example makes the current Meteor user available in a component, and causes Svelte to update the appropriate element automatically when the current user changes:

<script>
  import { useTracker } from 'meteor/rdb:svelte-meteor-data';

  const currentUser = useTracker(() => Meteor.user());
</script>

<h1>Welcome {$currentUser.username}!</h1>

You can even mix Meteor reactivity with Svelte reactivity:

<script>
  import { useTracker } from 'meteor/rdb:svelte-meteor-data';

  let selectedUserId;

  $: selectedUser = useTracker(() => Meteor.users.findOne(selectedUserId));
</script>

<p>Selected {$selectedUser.username}</p>

Cursors

While it's possible to use queries with useTracker(() => query.fetch()), this package supports a more convenient way to handle reactive queries, by allowing you to use a MongoDB cursor directly as a Svelte store:

<script>
  export let fruitColor = 'blue';

  $: fruits = Fruits.find({color: fruitColor});
</script>

<p>Showing {$fruits.length} {fruitColor}-colored fruits:</p>
<ul>
  {#each $fruits as fruit}
    <li>{fruit.name}</li>
  {/each}
</ul>

Subscriptions

You can safely use Meteor.subscribe in your components without worrying about clean-up. The subscription will be stopped automatically when the component is destroyed.

As an added feature, you can use a subscription handle in an {#await} block:

{#await Meteor.subscribe('todos')}
  <p>Loading todos…</p>
{:then}
  <TodoList />
{/await}

Tracker.autorun

It is possible to use Tracker.autorun() with a function that is automatically re-run when its Meteor dependencies change. It will stop being updated when the component is destroyed. This will work fine for top-level computations that do not depend on any dynamic Svelte state, such as in this example:

<script>
  let currentUser;

  Tracker.autorun(() => {
    currentUser = Meteor.user();
  });
</script>

To make the autorun also respond to Svelte state changes, you need to put it under a $: block. This will work, but with some caveats: if the Tracker state is invalidated right after a change to the Svelte state, all $: blocks will be re-run. It is therefore better to use useTracker instead, as listed above.

ReactiveVar

A Meteor ReactiveVar will work seamlessly as a Svelte store, and can be accessed and bound like any writable store using the $ operator:

<script>
  import { ReactiveVar } from 'meteor/reactive-var';

  const store = new ReactiveVar("initial");
</script>

<input type="text" bind:value={$store} />

<p>Value is {$store}</p>

Session variables

If you are using Meteor Session variables, these can be exposed as a reactive Svelte store using the useSession hook. The first argument is the session key to expose, and the optional second argument allows you to set a default value for the session variable, as an added convenience.

This function is only available if the session package has been added.

<script>
  import { useSession } from 'meteor/rdb:svelte-meteor-data';

  const store = useSession('mySessionKey', 'initial');

  // The above is equivalent to:
  //Session.setDefault('mySessionKey', 'initial')
  //const store = useSession('mySessionKey');
</script>

<input type="text" bind:value={$store} />

<p>Value is {$store}</p>

svelte-meteor-data's People

Contributors

rdb avatar red-meadow avatar renanccastro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

svelte-meteor-data's Issues

More complex example?

Sorry to use an issue tracker for a question...

While I've seen several examples of simple apps using this library, I have not seen a more realistic real-world example which has multiple deeper components, where if the database is changed, all updates are propagated properly.

In my case, I'm trying to do something like the following. Note that I have worked with Meteor a very long time ago, but not recently, and never Svelte, so there could be a learning curve. I'm also very much a back-end engineer, and yes, I'm making a web app. Be afraid.

I have a "planet" object which has this general shape:

{
  "system": "Sol",
  "number": 3,
  "resources": [
    { "name": "iron", "quantity": 4.5, "tapped": false },
    { "name": "copper", "quantity": 3.6, "tapped": false}
  ]
}

I have a component which does:

    $: planets = useTracker(() => Planets.find({}).fetch());

and then uses an {#each $planets as planet}<Planet {planet}/>{/each} to render the list. This works, and adding, removing, etc. make the list update properly. However, it seems changing the entries inside of the objects does not cause any sub-components of to re-render. That is, it seems the change detection works one level down, but anything lower than the first component seems to not work.

In this case, prints out planet.name, and then calls another component to render the planet.resources, one at a time, with a string provided for the one to render. This part does not update if the values change.

Do you have an example at hand that will propagate the reactive changes through components without having to re-fetch the item from the database in each component to ensure updates are properly triggered?

The hack is to pass the planet._id, and then fetch it in each component again, which while local is fast enough, this seems wrong.

Would you consider releasing a separate package with the svelte meteor helper functions?

Hi there,

I've been using your package in a project and it's been great. Thank you for putting it together.

I recently moved to zodern:melte to take advantage of the hot module replacement but I think useTracker and useSession in particular are super handy. I think it might be beneficial for folks using meteor and svelte to have a separate package with just those types of functions. What do you think?

A reactive subscription creates infinite amount of subscriptions when props change

When I create a subscription that reacts to changing props like so:

<script>
export let page;
$: Meteor.subscribe('stuff', { page });
</script>

...the old subscriptions will not be stopped until the component is destroyed. That means, if page changes a lot, a lot of "stale" subscriptions will be persisted until the component is destroyed.

Screenshot 2020-07-24 at 15 28 24

Wouldn't it make sense to close the old subscription when the props change?

Meteor user data not updated using useTracker

Hi, I have this piece of code, which I got from the tutorial in Meteor website:

$: currentUser = useTracker(() => Meteor.user())

The problem is, it's not rerun when I change the user's info (or even just logging out).

But when I do this, it reruns as expected:

// get current user
let currentuser
$: {
  Tracker.autorun(() => (currentUser = Meteor.user()))
  console.log('user:', currentuser)
}

Any help with this is appreciated, thanks!

benefit of calling useTracker

What is the difference between lines 3 and 4 below? Both seem to give me a Svelte store that updates whenever the task collection changes.

const query = {};
const projection = { sort: { createdAt: -1 } };
$: tasks1 = useTracker(() => Tasks.find(query, projection).fetch());
$: tasks2 = Tasks.find(query, projection);

await Meteor.subscribe doesn't work?

i've found this doesn't work

{#await Meteor.subscribe('todos')}
  <p>Loading todos…</p>
{:else}
  <TodoList />
{/if}

is this right?

{#await Meteor.subscribe('todos')}
  <p>Loading todos…</p>
{:then}
  <TodoList />
{/await}

and below code useTracker return a meteor subhandler

index.mjs:1643 Uncaught Error: {#each} only iterates over array-like objects.

what's wrong?

image

<Layout>
  <div>admin categories</div>
  {#await Meteor.subscribe('categories')}
  {:then}
    <List isTop={true} categories={categories} />
  {/await}
</Layout>

<script>
  import Layout from '../layout'
  import List from './list'
  let loading = true
  let categories = useTracker(() => Categories.find().fetch())
  console.log('test', categories)
</script>

Make Tracker.autorun work inside $:

The problem right now is that if you have code like this:

let svelteProp;

$: Tracker.autorun(() => {something with svelteProp});

The previous autorun won't stop when svelteProp changes, and you'll get two of them running.

This will be tricky to do without hooking into the generated Svelte code somehow, but it may be possible by doing one of these:

  • Having the autorun run every time any Svelte state whatsoever changes (but I can't think of a way to do this without breaking the topological dependency ordering).
  • Invalidating the entire Svelte component whenever the autorun is invalidated.

Auto-stop cursor.observe and cursor.observeChanges

It would be convenient if cursor.observe/observeChanges would also auto-stop when the component is destroyed.

Come to think of it, it might be a wild goose chase to track down and monkey patch all the places where this would be useful. Perhaps it is possible to find a way to either automatically wrap the whole component in a Tracker.Computation or to patch Tracker.onInvalidate somehow.

Make svelte:compiler a weak dependency

The svelte:compiler package requires apps to use a specific svelte version and warns when the app uses a different version. When apps or packages use zodern:melte instead, they can use the latest svelte version, but if they also use rdb:svelte-meteor-data they get shown the warning from svelte:compiler to use an older version of svelte:

WARNING: this package requires [email protected] to be installed as npm peer dependency, but your package.json specifies:

  "svelte": "^3.44.2"

If you encounter error messages, consider running:

  meteor npm install --save [email protected]

If you make svelte:compiler a weak dependency, then apps can use the latest svelte version with zodern:melte and rdb:svelte-meteor-data without seeing the warning.

meteor/reactive-dict

i see there're session, reactive-var and all others wrapper except meteor/reactive-dict

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.