Categories
React

Add Charts into Our React App with Nivo — Radar 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.

Radar Chart

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

To install the required packages, we run:

npm i @nivo/radar

Then we can add the chart by writing:

import React from "react";
import { ResponsiveRadar } from "@nivo/radar";

const data = [
  {
    taste: "fruity",
    chardonay: 92,
    carmenere: 57,
    syrah: 92
  },
  {
    taste: "bitter",
    chardonay: 68,
    carmenere: 44,
    syrah: 55
  },
  {
    taste: "heavy",
    chardonay: 63,
    carmenere: 31,
    syrah: 26
  }
];

const MyResponsiveRadar = ({ data }) => (
  <ResponsiveRadar
    data={data}
    keys={["chardonay", "carmenere", "syrah"]}
    indexBy="taste"
    maxValue="auto"
    margin={{ top: 70, right: 80, bottom: 40, left: 80 }}
    curve="linearClosed"
    borderWidth={2}
    borderColor={{ from: "color" }}
    gridLevels={5}
    gridShape="circular"
    gridLabelOffset={36}
    enableDots={true}
    dotSize={10}
    dotColor={{ theme: "background" }}
    dotBorderWidth={2}
    dotBorderColor={{ from: "color" }}
    enableDotLabel={true}
    dotLabel="value"
    dotLabelYOffset={-12}
    colors={{ scheme: "nivo" }}
    fillOpacity={0.25}
    blendMode="multiply"
    animate={true}
    motionConfig="wobbly"
    isInteractive={true}
    legends={[
      {
        anchor: "top-left",
        direction: "column",
        translateX: -50,
        translateY: -40,
        itemWidth: 80,
        itemHeight: 20,
        itemTextColor: "#999",
        symbolSize: 12,
        symbolShape: "circle",
        effects: [
          {
            on: "hover",
            style: {
              itemTextColor: "#000"
            }
          }
        ]
      }
    ]}
  />
);

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

We define the data array to add the data for the radar chart.

Then we pass that into the data prop.

keys have the names for the legend items.

indexBy has the property name for the point text.

maxValue has the max value, which is automatically computed.

margin has the margins.

curve has the line style for the background.

borderWidth has the border width.

borderColor has the border color.

gridLeve;ls have the number of lines for the background.

gridShape has the grid shape.

dotSize has the point size.

dotBorderWidth and dotBorderColor have the dot border width and color.

fillOpacity have the fill opacity for the radar chart items.

animate andmotionConfig are the animation config.

isInteractive enables display when hovering over items.

legends have the legend settings.

We translate it and set the item dimensions.

effects have a hover effect when we hover over the legend items.

Then in App , we set the width and height to render the chart.

Conclusion

We can render radar charts easily in our React app with Nivo.

Categories
React

Add Charts into Our React App with Nivo — Pie Chart

Nivo 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.

Pie Chart

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

To install the required packages, we run:

npm i @nivo/pie

Then we can add the chart by writing:

import React from "react";
import { ResponsivePie } from "@nivo/pie";

const data = [
  {
    id: "c",
    label: "c",
    value: 120,
    color: "hsl(271, 70%, 50%)"
  },
  {
    id: "stylus",
    label: "stylus",
    value: 174,
    color: "hsl(292, 70%, 50%)"
  },
  {
    id: "go",
    label: "go",
    value: 225,
    color: "hsl(47, 70%, 50%)"
  }
];

const MyResponsivePie = ({ data }) => (
  <ResponsivePie
    data={data}
    margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
    innerRadius={0.5}
    padAngle={0.7}
    cornerRadius={3}
    colors={{ scheme: "nivo" }}
    borderWidth={1}
    borderColor={{ from: "color", modifiers: [["darker", 0.2]] }}
    radialLabelsSkipAngle={10}
    radialLabelsTextColor="#333333"
    radialLabelsLinkColor={{ from: "color" }}
    sliceLabelsSkipAngle={10}
    sliceLabelsTextColor="#333333"
    defs={[
      {
        id: "dots",
        type: "patternDots",
        background: "inherit",
        color: "rgba(255, 255, 255, 0.3)",
        size: 4,
        padding: 1,
        stagger: true
      },
      {
        id: "lines",
        type: "patternLines",
        background: "inherit",
        color: "rgba(255, 255, 255, 0.3)",
        rotation: -45,
        lineWidth: 6,
        spacing: 10
      }
    ]}
    fill={[
      {
        match: {
          id: "ruby"
        },
        id: "dots"
      },
      {
        match: {
          id: "c"
        },
        id: "dots"
      },
      {
        match: {
          id: "go"
        },
        id: "dots"
      },
      {
        match: {
          id: "python"
        },
        id: "dots"
      },
      {
        match: {
          id: "scala"
        },
        id: "lines"
      },
      {
        match: {
          id: "lisp"
        },
        id: "lines"
      },
      {
        match: {
          id: "elixir"
        },
        id: "lines"
      },
      {
        match: {
          id: "javascript"
        },
        id: "lines"
      }
    ]}
    legends={[
      {
        anchor: "bottom",
        direction: "row",
        justify: false,
        translateX: 0,
        translateY: 56,
        itemsSpacing: 0,
        itemWidth: 100,
        itemHeight: 18,
        itemTextColor: "#999",
        itemDirection: "left-to-right",
        itemOpacity: 1,
        symbolSize: 18,
        symbolShape: "circle",
        effects: [
          {
            on: "hover",
            style: {
              itemTextColor: "#000"
            }
          }
        ]
      }
    ]}
  />
);

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

We define the data array with the pie data.

label has the pie chunk labels.

value has the pie chunk size values.

Then add the ResponsivePie component into our chart.

margin has the margins.

data has the pie chart data.

innerRadius has the inner radius size.

colors have the color scheme for the pie slices.

borderWidth has the border width.

borderColor has the border-color scheme.

radialLabelsSkipAngle defines the angle threshold for when the label is hidden.

If it’s smaller than the given size, then the label is hidden.

radialLabelsTextColor has the text color of the pie.

radialLabelsLinkColor has the labels link color.

sliceLabelsSkipAngle has the angle threshold for skipping rendering the slice label.

If it’s smaller than the given threshold, then the slice label is hidden.

sliceLabelsTextColor has the text color.

defs have the pattern definitions for the slices.

color have the pattern color.

type has the pattern type.

fill has the fill color for the slices and legend.

legends has the legend settings.

itemSpacing , itemWidth , itemHeight , itemTextColor , and itemDirection has the item dimensions, spacing, and color.

effects have the effects when we hover over the legend items.

Then in App , we set the width and height to render the pie chart.

Conclusion

We can add pie charts easily into our React app with Nivo.

Categories
Vue 3

Create Vue 3 Apps with the Composition API — Custom Refs and Shallow Reactivity

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.

customRef

We can use the customRef function to create a custom ref.

For instance, we can write:

<template>
  <div>
    <input v-model="text" />
    {{ text }}
  </div>
</template>

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

const useDebouncedRef = (value, delay = 200) => {
  let timeout;
  return customRef((track, trigger) => {
    return {
      get() {
        track();
        return value;
      },
      set(newValue) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          value = newValue;
          trigger();
        }, delay);
      },
    };
  });
};

export default {
  name: "App",
  setup() {
    return {
      text: useDebouncedRef("hello world"),
    };
  },
};
</script>

We create the useDebounceRef function that returns a custom ref created bu the customRef function.

It takes a callback with the track function to track the value.

And the setter calls trigger to trigger state updates.

We ser the value in the setter to newValue so that the items are updated.

markRaw

We can call the markRaw function to mark an object so that it’ll never be converted to a proxy.

For instance, we can write:

<template>
  <div></div>
</template>

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

export default {
  name: "App",
  setup() {
    const foo = markRaw({});
    console.log(isReactive(reactive(foo)));
    return { foo };
  },
};
</script>

The console log logs false since we called markRaw to disable reactivity on the object we passed into it.

But if we mark one object as raw and we reference that object in another object, then they’ll be considered not to be equal even though they have the same reference:

<template>
  <div></div>
</template>

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

export default {
  name: "App",
  setup() {
    const foo = markRaw({
      nested: {},
    });

    const bar = reactive({
      nested: foo.nested,
    });

    console.log(foo.nested === bar.nested);
    return { foo };
  },
};
</script>

We set bar.nested to foo.nested , but the console log is false .

shallowReactive

We can create a shallow reactive object with the shallowReactive function.

The reactive property is limited to the top-level properties of the object.

For instance, we can write:

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

<script>
import { isReactive, shallowReactive } from "vue";

export default {
  name: "App",
  setup() {
    const state = shallowReactive({
      foo: 1,
      nested: {
        bar: 2,
      },
    });

    const increment = () => {
      state.foo++;
      state.nested.bar++;
    };
    console.log(isReactive(state.nested.bar));
    return { state, increment };
  },
};
</script>

In the increment function, we increment both state.foo and state.nested.bar and they’ll both update in the template.

But when we log state.nested.bar with isReactive , we get false logged.

Since it’s not reactive, it won’t trigger watchers to run:

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

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

export default {
  name: "App",
  setup() {
    const state = shallowReactive({
      foo: 1,
      nested: {
        bar: 2,
      },
    });

    const increment = () => {
      state.foo++;
      state.nested.bar++;
    };

    watch(state.nested.bar, (bar) => {
      console.log(bar);
    });

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

Then watch callback in the 2nd argument won’t run when state.nested.bar is updated.

Conclusion

We can use various functions provided Vue 3’s composition API to create various kinds of reactive and non-reactive properties.

Categories
Vue 3

Create Vue 3 Apps with the Composition API — Check Reactive Properties

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.

toRefs

We can use the toRefs function to convert a ref toa plain object.

For instance, we can write:

<template>
  <div></div>
</template>

<script>
import { reactive, toRefs } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });

    const stateAsRefs = toRefs(state);
    console.log(stateAsRefs);

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

to convert the state reactive property to a plain object.

state.foo and stat.bar are reactive properties with values being the values that we set in the reactive function.

isRef

The isRef function checks if a variable is a ref.

For instance, we can write:

<template>
  <div></div>
</template>

<script>
import { isRef, reactive, ref } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });

    const r = ref(0);
    console.log(isRef(state));
    console.log(isRef(r));

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

We call isRef with state , which returns false .

And when we call isRef with r , it returns true .

isProxy

The isProxy function checks if an object is reactive or read-only.

For instance, we can write:

<template>
  <div></div>
</template>

<script>
import { isProxy, reactive, readonly, ref } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });
    const ro = readonly({ foo: 1 });

    const r = ref(0);
    console.log(isProxy(state));
    console.log(isProxy(ro));
    console.log(isProxy(r));

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

The first 2 console logs are log true since we created variables with reactive and readonly .

And the 3rd one logs false since a ref isn’t created with reactive or readonly .

isReactive

We can check if a variable is created from reactive with isReactive .

For instance, we can write:

<template>
  <div></div>
</template>

<script>
import { isReactive, reactive, readonly, ref } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });
    const ro = readonly({ foo: 1 });

    const r = ref(0);
    console.log(isReactive(state));
    console.log(isReactive(ro));
    console.log(isReactive(r));

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

Only state is created with the reactive function, so only the first console log logs true .

isReadonly

We can check if a variable is created with readonly is isReadonly .

For instance, we can write:

<template>
  <div></div>
</template>

<script>
import { isReadonly, reactive, readonly, ref } from "vue";
export default {
  name: "App",
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });
    const ro = readonly({ foo: 1 });

    const r = ref(0);
    console.log(isReadonly(state));
    console.log(isReadonly(ro));
    console.log(isReadonly(r));

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

to call isReadonly .

Only the 2nd console log logs true since only ro is created with readonly .

Conclusion

We can use various functions from the Vue 3 composition API to do various checks on reactive properties.

Categories
Vue 3

Create Vue 3 Apps with the Composition API — Refs

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.

Using Refs with v-for

We can assign refs to items rendered with v-for .

For instance, we can write:

<template>
  <div
    v-for="(item, i) in list"
    :ref="
      (el) => {
        divs[i] = el;
      }
    "
    :key="i"
  >
    {{ item }}
  </div>
</template>

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

export default {
  setup() {
    const list = reactive([1, 2, 3]);
    const divs = ref([]);

    onBeforeUpdate(() => {
      divs.value = [];
    });

    return {
      list,
      divs,
    };
  },
};
</script>

We create the divs reactive property with the ref function.

Then when we render the items with v-for , we assign the el HTML element object as an entry of the divs array.

Reactivity Utilities

The Vue 3 composition API comes with some utility functions to do various things with reactive properties.

unref

The unref function lets us return the ref’s value or the argument we pass into the ref function depending on if the variable is a ref.

For instance, we can write:

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

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

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

We create the count reactive property.

And in the watch callback, we call unref(count) to get the actual value of the count reactive property.

If it’s not a ref, it returns the value of the variable we pass in.

toRef

The toRef function lets us create a ref for a property on a reactive source object.

For instance, we can write:

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

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

    const count = toRef(state, "count");
    const increment = () => {
      state.count++;
    };

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

We call toRef to create a ref from the state.count property.

Now we can include it in the object we return and then reference it in the template.

This is useful if we want to pass it into a composition function.

For instance, we can write:

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

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

    const count = toRef(state, "count");
    const increment = () => {
      state.count++;
    };

    watch(count, (count) => console.log(count));

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

We pass the count into watch so we can watch its value.

Conclusion

We can assign refs to HTML elements to let us access them in our component.

And we can manipulate refs with various functions that comes with Vue 3’s composition API.