Categories
Vue 3

Create Vue 3 Apps with the Composition API — Watch and Watch Effect

Vue 3 comes with the Composition API built-in.

It lets us extract logic easily an not have to worry about the value of this in our code.

It also works better with TypeScript because the value of this no longer has to be typed.

In this article, we’ll look at how to create Vue 3 apps with the Composition API.

watch

The watch function in the Vue 3 composition API is the same as Vue 2’s this.$watch method or the watch option.

Therefore, we can use it to watch for changes in reactive properties.

For instance, we can write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.count }}
  </div>
</template>

<script>
import { reactive, watch } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({ count: 0 });

    const increment = () => {
      state.count++;
    };
    watch(
      () => state.count,
      (count, prevCount) => {
        console.log(count, prevCount);
      }
    );

    return {
      state,
      increment,
    };
  },
};
</script>

We watch a getter function in the 2nd argument.

And we get the current and previous value in the first and 2nd parameter of the function we pass into watch as the 2nd argument.

Now when we click on the increment button, we see state.count increase.

If we have a primitive valued reactive property, we can pass it straight into the first argument of watch :

<template>
  <div>
    <button @click="increment">increment</button>
    {{ count }}
  </div>
</template>

<script>
import { ref, watch } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    const increment = () => {
      count.value++;
    };
    watch(count, (count, prevCount) => {
      console.log(count, prevCount);
    });

    return {
      count,
      increment,
    };
  },
};
</script>

And we get the same values we for count and prevCount when we click on the increment button.

Watching Multiple Sources

We can also watch multiple refs.

For instance, we can write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ foo }}
    {{ bar }}
  </div>
</template>

<script>
import { ref, watch } from "vue";
export default {
  name: "App",
  setup() {
    const foo = ref(0);
    const bar = ref(0);
    const increment = () => {
      foo.value++;
      bar.value++;
    };
    watch([foo, bar], ([foo, bar], [prevFoo, prevBar]) => {
      console.log([foo, bar], [prevFoo, prevBar]);
    });

    return {
      foo,
      bar,
      increment,
    };
  },
};
</script>

We pass in the foo and bar refs into the array.

Then we get the current and previous values from the arrays in the parameters of the function in the 2nd argument.

We can also pass in the onInvalidate function into the 3rd argument.

And other behaviors are also shared with watchEffect .

Conclusion

We can watch reactive properties with Vue 3’s composition API watchers.

Categories
Vue 3

Create Vue 3 Apps with the Composition API — Read-Only Properties and Side Effects

Vue 3 comes with the Composition API built-in.

It lets us extract logic easily an not have to worry about the value of this in our code.

It also works better with TypeScript because the value of this no longer has to be typed.

In this article, we’ll look at how to create Vue 3 apps with the Composition API.

Read-Only Property

We can add a read-only property to our Vue 3 app with the composition API.

To add it, we use the readonly property:

<template>
  <div>{{ copy }}</div>
</template>

<script>
import { reactive, readonly } from "vue";
export default {
  name: "App",
  setup() {
    const original = reactive({ count: 0 });
    const copy = readonly(original);
    return {
      copy,
    };
  },
};
</script>

We define the original reactive property with reactive .

Then we call readonly with original to create a read-only deep copy of the original.

And we return it, so we can use it.

Watch Reactive Properties

We can watch reactive properties with the watchEffect method.

For instance, we can write:

<template>
  <div>{{ count }}</div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    watchEffect(() => console.log(count.value));

    setTimeout(() => {
      count.value++;
    }, 100);

    return {
      count,
    };
  },
};
</script>

We call watchEffect with a callback to log the value of count when it’s updated in the setTimeout callback.

watchEffect returns a function that we can use to stop the watcher.

To use it, we write:

<template>
  <div>{{ count }}</div>
</template>

<script>
import { onBeforeUnmount, ref, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    const stop = watchEffect(() => console.log(count.value));

    setTimeout(() => {
      count.value++;
    }, 100);

    onBeforeUnmount(() => stop());

    return {
      count,
    };
  },
};
</script>

We call stop in the onBeforeUnmount callback to stop the watcher when we’re unmounting the component.

Also, we can invalidate side effects with the onInvalidate function.

For instance, we can write:

<template>
  <div>{{ size }}</div>
</template>

<script>
import { onBeforeMount, reactive, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const size = reactive({
      width: 0,
      height: 0,
    });

    const onResize = () => {
      size.width = window.innerWidth;
      size.height = window.innerHeight;
    };
    onBeforeMount(() => window.addEventListener("resize", onResize));

    watchEffect((onInvalidate) => {
      onInvalidate(() => {
        window.removeEventListener("resize", onResize);
      });
    });

    return {
      size,
    };
  },
};
</script>

to call window.removeEventListener to remove the event listener in the onInvalidate callback.

The onResize function sets the size when we change the screen by attaching it as the listener for the resize event.

Conclusion

We can add read-only properties and watch side effects with Vue 3’s composition API.

Categories
Vue 3

Create Vue 3 Apps with the Composition API

Vue 3 comes with the Composition API built-in.

It lets us extract logic easily an not have to worry about the value of this in our code.

It also works better with TypeScript because the value of this no longer has to be typed.

In this article, we’ll look at how to create Vue 3 apps with the Composition API.

Basic Example

We can create a basic app by defining reactive properties and using them in templates.

For instance, we can write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ count }}
  </div>
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    const count = ref(0);

    function increment() {
      count.value++;
    }

    return {
      count,
      increment,
    };
  },
};
</script>

We define the count reactive property with the ref function.

0 is its initial value.

And we add the increment function to update its value.

It’s updated differently than in the options API. We’ve to update the value property to update a reactive property with primitive values.

Then we return both count and increment so we can use them our template.

setup is a method that runs when we mount the component.

We can define object valued reactive properties with the reactive function.

To do this, we write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.count }}
  </div>
</template>

<script>
import { reactive } from "vue";

export default {
  setup() {
    const state = reactive({
      count: 0,
    });
    function increment() {
      state.count++;
    }

    return {
      state,
      increment,
    };
  },
};
</script>

We call reactive with an initial object value.

Then we assign it to the state reactive property.

In the increment function, we update the state.count property to update its value.

And we return state and count so we can use them in the template.

Computed Property

To create a computed property, we can use the computed function.

To do this, we write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.count }}
    {{ double }}
  </div>
</template>

<script>
import { reactive, computed } from "vue";

export default {
  setup() {
    const state = reactive({
      count: 0,
    });
    const double = computed(() => state.count * 2);

    function increment() {
      state.count++;
    }

    return {
      state,
      double,
      increment,
    };
  },
};
</script>

We pass a callback into the computed method to return the value we want for the computed property.

computed can be called in the object that we pass into reactive to add the computed property as a property of another reactive property.

Watchers

We can add a watcher into our Vue app with the watch function.

For instance, we can write:

<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.count }}
  </div>
</template>

<script>
import { reactive, watch } from "vue";

export default {
  setup() {
    const state = reactive({
      count: 0,
    });
    function increment() {
      state.count++;
    }
    watch(
      () => state.count,
      (count) => {
        console.log(count);
      },
      { immediate: true }
    );
    return {
      state,
      increment,
    };
  },
};
</script>

to add it.

The first argument of watch is a function that returns the state.count reactive property.

In the 2nd argument, we get the latest value of state.count with count and log it.

The 3rd argument is an object with options for the watcher.

We can set deep and immediate in there as we do with the options API.

deep means watch all nested properties of an object for changes.

immediate means the watcher runs immediately when the component is mounted.

Conclusion

We can use the Vue 3 Composition API to define our components.

All the things we have in the options API are still available with some improvements.

Categories
React

Add Charts into Our React App with Nivo — Parallel Coordinates Chart

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Nivo.

Parallel Coordinates Chart

Nivo comes with code to let us add a parallel coordinates chart into our React app.

To install the required packages, we run:

npm i @nivo/parallel-coordinates

Then we can add the chart by writing:

import React from "react";
import { ResponsiveParallelCoordinates } from "@nivo/parallel-coordinates";

const data = [
  {
    temp: 24,
    cost: 32344,
    color: "green",
    target: "D",
    volume: 3.32478102470854
  },
  {
    temp: 19,
    cost: 100448,
    color: "green",
    target: "E",
    volume: 5.052307538977317
  },
  {
    temp: 32,
    cost: 266169,
    color: "yellow",
    target: "D",
    volume: 4.657311172596244
  },
  {
    temp: 8,
    cost: 84370,
    color: "green",
    target: "D",
    volume: 0.6268058953310531
  },
  {
    temp: 21,
    cost: 304422,
    color: "red",
    target: "D",
    volume: 3.3590163049771173
  },
  {
    temp: -7,
    cost: 152254,
    color: "yellow",
    target: "C",
    volume: 6.019571437532089
  },
  {
    temp: 3,
    cost: 241390,
    color: "red",
    target: "E",
    volume: 1.0655003648315398
  },
  {
    temp: 15,
    cost: 277920,
    color: "yellow",
    target: "C",
    volume: 0.700657465435478
  },
  {
    temp: 12,
    cost: 294237,
    color: "green",
    target: "B",
    volume: 5.221829062361729
  },
  {
    temp: 34,
    cost: 363216,
    color: "red",
    target: "A",
    volume: 1.9905418770819305
  },
  {
    temp: -5,
    cost: 347671,
    color: "green",
    target: "B",
    volume: 1.287223272665619
  }
];

const MyResponsiveParallelCoordinates = ({ data /* see data tab */ }) => (
  <ResponsiveParallelCoordinates
    data={data}
    variables={[
      {
        key: "temp",
        type: "linear",
        min: "auto",
        max: "auto",
        ticksPosition: "before",
        legend: "temperature",
        legendPosition: "start",
        legendOffset: 20
      },
      {
        key: "cost",
        type: "linear",
        min: 0,
        max: "auto",
        ticksPosition: "before",
        legend: "cost",
        legendPosition: "start",
        legendOffset: 20
      },
      {
        key: "color",
        type: "point",
        padding: 1,
        values: ["red", "yellow", "green"],
        legend: "color",
        legendPosition: "start",
        legendOffset: -20
      },
      {
        key: "target",
        type: "point",
        padding: 0,
        values: ["A", "B", "C", "D", "E"],
        legend: "target",
        legendPosition: "start",
        legendOffset: -20
      },
      {
        key: "volume",
        type: "linear",
        min: 0,
        max: "auto",
        legend: "volume",
        legendPosition: "start",
        legendOffset: -20
      }
    ]}
    margin={{ top: 50, right: 60, bottom: 50, left: 60 }}
  />
);

export default function App() {
  return (
    <div style={{ width: 400, height: 300 }}>
      <MyResponsiveParallelCoordinates data={data} />
    </div>
  );
}

We add the data array to store the data that we’ll render in our chart.

temp and const are the values.

color have the line colors.

variables have the lines.

key has the property name with the value for the line.

type has the type of line.

min and max have the min and max values. They are calculated automatically if we set them to 'auto' .

ticksPosition sets the tick position.

legend has the legend value.

legendPosition has the position of the legend item.

legendOffset has the legend offset.

margin have the margins.

In App , we render the chart by setting the width and height.

Conclusion

We can add a parallel coordinates chart easily into our React app with Nivo.

Categories
React

Add Charts into Our React App with Nivo — Marimekko Chart

The Victory lets us add charts and data visualization into our React app.

In this article, we’ll look at how to add charts into our React app with Nivo.

Marimekko Chart

Nivo comes with code to let us add a Marimekko chart into our React app.

To install the required packages, we run:

npm i @nivo/marimekko

Then we can add the chart by writing:

import React from "react";
import { ResponsiveMarimekko } from "@nivo/marimekko";

const data = [
  {
    statement: "it's good",
    participation: 19,
    stronglyAgree: 12,
    agree: 30,
    disagree: 19,
    stronglyDisagree: 31
  },
  {
    statement: "it's sweet",
    participation: 11,
    stronglyAgree: 30,
    agree: 2,
    disagree: 1,
    stronglyDisagree: 16
  },
  {
    statement: "it's spicy",
    participation: 19,
    stronglyAgree: 15,
    agree: 22,
    disagree: 4,
    stronglyDisagree: 18
  }
];

const MyResponsiveMarimekko = ({ data }) => (
  <ResponsiveMarimekko
    data={data}
    id="statement"
    value="participation"
    dimensions={[
      {
        id: "disagree strongly",
        value: "stronglyDisagree"
      },
      {
        id: "disagree",
        value: "disagree"
      },
      {
        id: "agree",
        value: "agree"
      },
      {
        id: "agree strongly",
        value: "stronglyAgree"
      }
    ]}
    innerPadding={9}
    axisTop={null}
    axisRight={{
      orient: "right",
      tickSize: 5,
      tickPadding: 5,
      tickRotation: 0,
      legend: "",
      legendOffset: 0
    }}
    axisBottom={{
      orient: "bottom",
      tickSize: 5,
      tickPadding: 5,
      tickRotation: 0,
      legend: "participation",
      legendOffset: 36,
      legendPosition: "middle"
    }}
    axisLeft={{
      orient: "left",
      tickSize: 5,
      tickPadding: 5,
      tickRotation: 0,
      legend: "opinions",
      legendOffset: -40,
      legendPosition: "middle"
    }}
    margin={{ top: 40, right: 80, bottom: 100, left: 80 }}
    colors={{ scheme: "spectral" }}
    borderWidth={1}
    borderColor={{ from: "color", modifiers: [["darker", 0.2]] }}
    defs={[
      {
        id: "lines",
        type: "patternLines",
        background: "rgba(0, 0, 0, 0)",
        color: "inherit",
        rotation: -45,
        lineWidth: 4,
        spacing: 8
      }
    ]}
    fill={[
      {
        match: {
          id: "agree strongly"
        },
        id: "lines"
      },
      {
        match: {
          id: "disagree strongly"
        },
        id: "lines"
      }
    ]}
    legends={[
      {
        anchor: "bottom",
        direction: "row",
        justify: false,
        translateX: 0,
        translateY: 80,
        itemsSpacing: 0,
        itemWidth: 140,
        itemHeight: 18,
        itemTextColor: "#999",
        itemDirection: "right-to-left",
        itemOpacity: 1,
        symbolSize: 18,
        symbolShape: "square",
        effects: [
          {
            on: "hover",
            style: {
              itemTextColor: "#000"
            }
          }
        ]
      }
    ]}
  />
);

export default function App() {
  return (
    <div style={{ width: 400, height: 300 }}>
      <MyResponsiveMarimekko data={data} />
    </div>
  );
}

We have the data array which has the bar segment values.

The bar segment values are the numeric properties.

In the MyResponsiveMarimekko component, we set the data prop to the data array.

value has the chart title.

dimensions have the property names with the bar segment values as the value of value .

innerPadding has the passing of the chart.

axisRight have the right axis.

We set the tick styles with tickSize , tickPadding , and tickRotation .

axisBottom have the bottom axis styles.

axisLeft have the left axis styles.

We shift the legend text with legendOffset .

margin has the margins.

colors have the colors.

borderColor have the chart border color.

defs has the styles for the background lines.

fill has the fill we want to set for some bar segments.

legends have the legend styles.

itemSpacing , itemWidth , itemHeight , itemTextColor , itemDirection have the item styles.

effects have the animation effect when we hover the legend items.

In App , we set width and height so that we can render the chart.

Conclusion

We can add bar charts with custom width bars with the Marimekko component that comes with Nivo.