Monday, 5 February 2024 - Amsterdam

VueJS introduction: Solar system

Why VueJS

I was sort of forced to use VueJS so it seemed like a good time to dive into it a bit. It is often mentioned as an alternative for React.

Vue component structure

A typical Vue component consists of a <template> section, followed by a <script> section and then closing with a <style> section. These three areas can be seen here in a list component. Note that the filename is ItemsList.vue.


// src/components/ItemsList.vue

<template>
    <main>
        <section v-for="planet in planets" :key="planet.name">
            <header @click="selectPlanet(planet)">
                <img :src="planet.image" width="100" :alt="planet.name" />
                <h1>{{ planet.name }}</h1>
            </header>
        </section>
    </main>
</template>

<script>
export default {
    name: "ItemsList",
    props: {
        msg: String,
        planets: Array,
        selectPlanet: Function
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
main {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    color: white;
}

h3 {
    margin: 40px 0 0;
}
ul {
    list-style-type: none;
    padding: 0;
}
li {
    display: inline-block;
    margin: 0 10px;
}
a {
    color: #42b983;
}
</style>

It receives an array of planets to be listed via props. The App component in the root of the folder, loads the planet data and then passes it to the list component.


// src/App.vue

<template>
    <div>
        <ItemsList
            msg="message from parent"
            :planets="planets"
            :selectPlanet="this.selectPlanet"
        />
        <PlanetDetail
            v-if="selectedPlanet"
            :selectedPlanet="this.selectedPlanet"
            :close="this.selectPlanet"
        />
    </div>
</template>

<script>
import ItemsList from "./components/ItemsList";
import PlanetDetail from "./components/PlanetDetail";
import { loadData } from "./data/data";

export default {
    name: "App",
    components: {
        ItemsList,
        PlanetDetail
    },
    created() {
        this.loadData();
    },
    methods: {
        loadData,
        selectPlanet: function(planet) {
            this.selectedPlanet = planet;
        }
    },
    data: function() {
        return {
            planets: [],
            selectedPlanet: undefined
        };
    }
};
</script>

<style>
#app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
}

body {
    background-color: black;
}
</style>

The script -> methods section defines the loadData method inside the component. It is imported on line 19 with import { loadData } from "./data/data"; That however does not execute the method. Execution happens in the created section.



created() {
    this.loadData();
}

When loadData is called, it retrieves the data from /data.json. this.planets gets updated directly in that export which is not great. Still as this is a demo I’ll leave it at that.

export const loadData = async function () {
    const resp = await fetch("/data.json");

    if (!resp.ok) {
        throw new Error("failed to get json data");
    }

    this.planets = await resp.json();
};

In a future update, I’d return the data and then set this.planets in the component where this method was called. That avoids confusing any future devs as to the context of this.

ItemsList

The App.vue component loads two custom components. The ItemList component is passed the planets data. With that data it shows a list of the planets.


<ItemsList
    msg="message from parent"
    :planets="planets"
    :selectPlanet="this.selectPlanet"
/>

The planets is passed to the ItemsList child component with this. :planets="planets" In this case the planets value that seems to be between strings is actually read as code in Vue.

With :selectPlanet="this.selectPlanet" the child component can call the method this.selectPlanet which exists in the parent. Line 32.

Source

The full project can be found here:

GitHub.com/Giwan/vue-solar-system