Vuex 4 in Vuejs 3, with the composition api

Too long to read: yes, you can use vuex 4 with the composition api. Hints on how to do this are, at present, hidden in git repo’s and discord channels, so I thought I’d share the secret here.

I used the code from github.com/vuejs/vuex/tree/4.0/examples/composition/counter as my starting point.

A template file could look like the below. I bolded the essential parts:

<template>
<div id="app">
Clicked: {{ count }} times, count is {{ evenOrOdd }}.
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">Increment if odd</button>
<button @click="incrementAsync">Increment async</button>
</div>
</template>

<script>
import { computed } from 'vue'
import { useStore, } from 'vuex'

export default {
name: 'counter',
setup () {
 const store = useStore();
  return {
   count: computed(() => store.state.count),
   evenOrOdd: computed(() => store.getters.evenOrOdd),
   increment: () => store.dispatch('increment'),
   decrement: () => store.dispatch('decrement'),
   incrementIfOdd: () => store.dispatch('incrementIfOdd'),
   incrementAsync: () => store.dispatch('incrementAsync')
  }
}}
</script>

That’s really the most difficult part 😁. But to complete the example, here’s how to include vuex in your main.js:

import { createApp } from 'vue'
import App from './App.vue'
import store from './store/store'

createApp(App)
.use(store)
.mount('#app')

And here’s how a sample store could look:

import { createStore } from 'vuex'

// root state object.
// each Vuex instance is just a single state tree.
const state = {
count: 0
}

// mutations are operations that actually mutate the state.
// each mutation handler gets the entire state tree as the
// first argument, followed by additional payload arguments.
// mutations must be synchronous and can be recorded by plugins
// for debugging purposes.
const mutations = {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}

// actions are functions that cause side effects and can involve
// asynchronous operations.
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement'),
incrementIfOdd ({ commit, state }) {
if ((state.count + 1) % 2 === 0) {
commit('increment')
}
},
incrementAsync ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('increment')
resolve()
}, 1000)
})
}
}

// getters are functions.
const getters = {
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
}

// A Vuex instance is created by combining the state, mutations, actions,
// and getters.
export default createStore({
state,
getters,
actions,
mutations
})

So far this post is nothing more than a search engine friendly way to share that git-repo. So thanks to kiaking as usual.

However, there is not much reason to do it this way, unless you want to extract some commonly used code into the composition api.

Say we want to use our timer in different places in our app, we could do it in two ways:

  1. We could move all the logic into vuex and use it directly in each place where we’re using the counter.
  2. We could create a composable – a javascript file that uses the composition api – in which we put our logic.

Personally I’m not quite sure yet which of these two routes I prefer.

However, the topic of this post is the composition API, I’ll follow the second route here:

//myComposable.js

import {computed} from "vue";
import {useStore} from 'vuex';

export const myComposable => {
 const store = useStore();
  return {
   count: computed(() => store.state.count),
   evenOrOdd: computed(() => store.getters.evenOrOdd),
   increment: () => store.dispatch('increment'),
   decrement: () => store.dispatch('decrement'),
   incrementIfOdd: () => store.dispatch('incrementIfOdd'),
   incrementAsync: () => store.dispatch('incrementAsync')
  }
}

To use the above in a component our setup method changes to the following:

<script>
import { computed } from 'vue'
import { myComposable } from '@/myComposable.js'

export default {
name: 'counter',
setup () {
  const {
   count,
   evenOrOdd,
   increment,
   decrement,
   incrementIfOdd,
   incrementAsync
  } = myComposable;
  return {
   count,
   evenOrOdd,
   increment,
   decrement,
   incrementIfOdd,
   incrementAsync
  }
}}
</script>

Now you can reuse the computed properties & methods from myComposable.js in any template file you like.

Reactivity and non-reactivity introduction for vue 2 and vue 3

We’re all excited that vuejs 3 is now out. However, how does it work?

If you want to use the new composition api, you’ll have to understand reactivity at a deeper level. The vue team agrees, because the new docs already include an explanation on reactivity.

However, after reading that and following some online courses, I still stumbled on some things that I wasn’t expecting.

reactivity & non-reactivity in vuejs 2.x (options api)

In vue 2, you’re expected to make everything reactive. That’s great, but in order to really understand what’s going on, the difference between reactive and non-reactive has to become clear. And being a dev, I think in code. So here is non-reactivity in vue 2:

<template>
  <div id="app">
    <h1>Reactivity in Vue 2.*</h1>
    <table>
      <tr>
        <td>reactive</td>
        <td>{{ count }}</td>
        <td><button @click="incrementReactive">increment reactive</button></td>
      </tr>
      <tr>
        <td>nonreactive</td>
        <td>{{ nonReactiveCount }}</td>
        <td>
          <button @click="incrementNonReactive">increment reactive</button>
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      count: 0,
    };
  },
  created() {
    this.nonReactiveCount = 0;
  },
  methods: {
    incrementReactive() {
      this.count++;
    },
    incrementNonReactive() {
      this.nonReactiveCount++;
    },
  },
};
</script>

As you can see, this.nonReactiveCount changes value when you click it’s button, but that change won’t show, until something reactive has updated.

What I hadn’t realised before is that non-reactivity in vue 2 doesn’t mean things don’t change. It means the app you’re building won’t listen to that change, so it won’t update.

reactivity and non-reactivity in vuejs 3.x

In vue 3 we could do precisely what I did above. And if you want to check that out, you can see it here. The only thing that’s changed is that we now need to call it by it’s name: the options-api.

However, the interesting part is of course when we start using the composition-api.

The main difference, from a reactivity standpoint, between the options and the composition-api is that with the options api reactivity is the default. With the composition-api, you manually create reactivity-instances each time you use it.

Using the composition api it looks like this.

<script>
import { ref } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    let nonReactiveCount = 0;

    return {
      count,
      nonReactiveCount,
    };
  },
  methods: {
    incrementReactive() {
      this.count++;
    },
    incrementNonReactive() {
      this.nonReactiveCount++;
    },
  },
};
</script>

So far so good. It behaves exactly the same. However, what happens when we move the methods themselves to the setup method?


  setup() {
    const count = ref(0);
    let nonReactiveCount = 0;
    const incrementReactive =() =>  {
      count.value++;
    }
    const incrementNonReactive = () => {
      nonReactiveCount++
    }
    return {
      count,
      nonReactiveCount,
      incrementReactive,
      incrementNonReactive
    };
  },

Now the incrementNonReactive-method no longer seems to work: nonReactiveCount doesn’t seem to increment. However, if you check the console, you’ll see that the value of nonReactiveCount DOES increase, however, the template-view doesn’t reflect that!

Clearly, in vue 3, reactivity through the composition api is more local than in the options api. When there’s a reactive change, the options api updates everything (within that vue instance) to the latest value, whereas the composition api updates only reactive values.

I thought this was a bug, but it turns out it’s more of a legacy feature.

After I posted the above, I got a LOT more help understanding this on the github issue I had posted. Since my conclusion there has been approved by core-team members, I’ll just repeat it here:

In the setup method I’ve set a variable ‘nonReactiveCount’ to 0. Its value gets exported to the vue-instance as the value of the exported ‘nonReactiveCount’ key. It’s not reactive.

I can increment this.nonReactiveCount through the methods, because it’s available on the ’this’. I can see that reflected in the template as soon as a reactive change updates the virtual dom. this.nonReactiveCount no longer has anything to do with the variable ‘nonReactiveCount’ in the setup method (and to correct my blogpost I guess I’ll be showing that).

Through the incrementNonReactive function in the setup method, I can increment the variable ‘nonReactiveCount’ within the setup method. However, other than logging it, nothing else happens with that new value, because the variable isn’t available outside the setup method.

It only seems like it’s exported because of various shorthands used in the code:
return { nonReactiveCount } means:
return { nonReactiveCount: value-of-nonReactiveCount }

nonReactiveCount does not (for instance) get re-exported when it changes. The export happens on setup (hence the name setup-method) and the value it has at that point is the value assigned to this.nonReactiveCount. this.nonReactiveCount and nonReactiveCount aren’t connected after that.

Thanks to Thorsten Lünborg(LinusBorg) for explaining.

Filter alternatives in vuejs

About three months ago I started using filters in my vue-template files. I created a whole formatter-library in our private NPM-repo with the aim to use the functions in there as filters. I had also started promoting this strategy (well discussed beforehand) with my colleauges. And then I found out that …

In vue 3 filters will no longer work. My colleagues, who have experience back to vue 1, tell me the vue-team has tried to get rid of filters before. They hope Evan and his team will change their minds for vue 3.1. However, if they don’t, there are decent alternatives.

So what are filters? They are a way to format input in a vue-template. The syntax looks like this:

<div>{{number | euro}}</div>

The ‘euro’ filter can format the number to include a euro sign and perhaps format the number in an EU-locally appropriate way.

I like this syntax because reading from left to write I first get the value and the variable the value is coming from and only then what it will be formatted as. Since the formatting is usually an (important) afterthought and rarely relevant for bug fixing, it makes sense to have it last.

There are basically two ways to circumvent filters for this purpose:

  • Methods
  • Computed properties

Methods

Using methods in templates feels off. It’s a rarely used method in the documentation and for obvious reasons: it means that the method gets called again and again, without caching. However, under the hood filters and methods are precisely the same thing, so it’s not an argument against methods as a replacement for filters. The syntax is pretty obvious:

<div>{{euro(number)}}</div>

Again: the euro method will transform the number into a string starting with a euro-sign. Just like a filter, but the syntax is just slightly less obvious on first sight. You will first notice that you’re dealing with euro’s and only then with the actual variable.

Computed properties

My template files are full of computed properties. From transformed data to simple references to my vuex-store. However, in order to use them to transform my data to something humanly legible I would have to do something like this (assuming my number isn’t coming from some long list of data):

computed: {
    number(){return 5},
    euroNumber(){ return this.euro(this.number) }
}
<template>
    <div>{{euroNumber}}</div>
</template>

This means that the underlying ‘number’ property is hidden behind the euroNumber property, which necessitates an extra step when debugging. However, this approach does mean that the resulting ‘euroNumber’ variable is cached, which can speed up the application, especially when there is a lot of data.

Conclusion

I will miss filters. When we transition over from vue2 to vue3, I guess we will mostly use methods instead.

NextTick vs setTimeout in Vue

TL;DR : what you want is probably setTimeout.

To understand the following, you may want to watch (or watch again) the famous ‘What the heck is the event-loop?‘ video by Philip Roberts. Five years old, and still relevant. Watch till the end, because we’re interested in the following three aspects of the way browsers render javascript:

  1. call stack
  2. render queue
  3. (async) callback queue / task queue

Philip Roberts only touches on the render queue briefly at the end, but for us it’s crucial.

The call-stack always has priority. When it’s empty, the browser will start outputting what’s in the render queue. When that’s done it’s time for the callback queue.

Basic problem

When you use Vue to calculate something difficult, like opening all the nodes in a tree with thousands of nodes (actual use-case), it takes a while. For the user, this may be confusing. So you want to give them some indication that: ‘yes, we’re working on it’, say some sort of animation. You probably also want to disable the button they just clicked.

The problem is that without some extra work, the browser will show the animation just as it finishes doing that long calculation. By which time you’ve turned the animation off. Pseudo-code sample:

this.animation = true;
this.calculationStart();
this.calculationStop();
this.animation = false

-> browser shows change in tree, animation never called.

What happens is that the render-queue isn’t called until both those calculations are done. Not good. What you want is something like this:

this.animation = true;

-> browser shows animation

this.calculationStart();

-> browser continues to show animation

this.calculationEnds();
this.animation = false;

> browser shows change in tree and stops showing animation. User happy (or happyish, because it did take a while)

So how come the second doesn’t happen? Because the render queue waits till the call stack is empty, before actually rendering. Our calculationStart ends up on the call stack and blocks it. The render queue doesn’t even get called, until the calculation is done.

Not good.

nextTick?

So how do we get our animation to start in the browser, before the calculation starts? You may have picked up on ‘nextTick’ and thought – that sounds promising.

In order to wait until Vue.js has finished updating the DOM after a data change, you can use Vue.nextTick(callback) immediately after the data is changed. The callback will be called after the DOM has been updated.

Vue documentation

Sounds good right? So I might do something like this:

this.animation = true;
this.nextTick( this.calculationStart() );
this.calculationEnds();
this.animation = false;

Unfortunately, this still doesn’t show our animation.

Sigh.

The ‘why’ is hidden in this stack-overflow answer:

nextTick allows you to do something after you have changed the data and VueJS has updated the DOM based on your data change, but before the browser has rendered those changed on the page.

Normally, devs use native JavaScript function setTimeout to achieve similar behavior. But, using setTimeoutrelinquishes control over to the browser before it gives control back to you via your callback.

Prasant at stack overflow

So – VueJS has updated the DOM, but the browser hasn’t actually RENDERED those DOM-changes yet. In other words: we’re still working within the call-stack. [or within microtasks, but for our purposes: same difference].

That’s not what we want. We want the DOM to change before that long calculation starts so our user knows what’s going on.

The solution is also given by Prasant: we use setTimeout. In most cases it’s quite enough to use 0 seconds, though I’ve sometimes gone for more.

So here’s our final pseudocode:

this.animation = true ;

-> browser renders animation because nothing left on the call-stack.

this.setTimeout( function(){this.calculationStart() }, 0)

-> browser moves this.calculationStart from callback queue onto the call stack and does ’this.calculationStart’

this.calculationEnds()
this.animation = false

Animation stops after calculation is done. Phew.

So what happened? setTimeout does it’s thing by putting it’s callback on the callback queue. The callback queue is only called by the browser after both the call stack and the render queue are done. So our animation (which is on the call stack) gets done, the render queue renders it, and then the browser is ready for the callback queue and calls the long-calculation.

This is what we want.

Vue Dev-tools for development in IE-11 / Windows

In order to debug IE11 (still about 40% of our users), I recently had to install vue-dev-tools, the electron-app version. Using it is a bit more involved than the chrome-extension or the firefox-addon. Also, in some of it’s setups, the electron-app can cause unwanted extra console-warnings (endless amounts), if you just want to use the chrome-extension.

So here is the setup I ended up using:

$ npm install vue-devtools --save-dev 

in main.js (or comparable):

import devtools from '@vue/devtools';
 if (process.env.NODE_ENV === 'development') {
   global.devtools = devtools;
 }

In your console, at your project root, run vue devtools with npx:

$ npx vue-devtools

En then in de browser console of the browser you’re checking (say IE11):

$ devtools.connect()

More complicated Leave animations in VueJS

I’ve been working with Vue for a few months now and I love the ease with which you can work css animations into it. However, when it came to creating an animation with two elements leaving the dom at the same time, I was stuck. I could also not find much help inline, so once I figured out a way, I thought I’d document it.

The trick is, basically, that when you want two elements to leave the dom at the same time, there has to be a containing element as well. It will also leave the dom. Unfortunately, once it has left the dom, the child elements (the ones you’re really interested in) will be gone as well. This means no fading or moving to the side or anything. Something that isn’t there will not show up as animating – bugger.

For this reason Vue has introduced the ‘duration’ prop. Here is some basic example vue template code:
<template>
<transition name="modal-main" :duration="500" >

    <transition-group name="modal-in-out" appear >

      <div class="class1"></div>

      <div class="class2"></div>

   </transition-group>

</transition>
</template>

The outside ’transition’ tag is for the containing element. The duration of 500 means that it will stay in the DOM for 500 ms after it’s been given the signal to leave.

This gives the ’transition-group’ the time to manage the two transitions on the two enclosed divs in there. In VueJS you need transition-group if you want to manage more than one animation at once.

To make it more complete, here are some animations you might want to use:

.modal-main-leave-active .class1 {

animation: fadeout 550ms cubic-bezier(0.605, 0.09, 0.37, 0.9);

}
.modal-main-leave-active .class2 {
animation: slideout 550ms cubic-bezier(0.605, 0.09, 0.37, 0.9);
}


@keyframes fadeout {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}


@keyframes slideout {
0% {
margin-left: 0%;
}
100% {
margin-left: 100%;
}
}

Note that while the ‘duration’ of the main transition is 500ms, the css animations are 550ms. The extra 50ms prevent a weird flickering effect at the end of the leave animation. Basically it means that the element will (for some reason) come back in the dom right after the animation stopped. By making sure that the containing element has left the DOM, I’m also making sure that the flickering doesn’t show. It’s a bit hacky, but it works.

Web Developer Certificaat van Codaisseur

Deze zomer (2017) heb ik  me verder verdiept in het programmeervak: bij Codaisseur heb ik me tot full stack developer ontwikkeld.

Voor wie het wat zegt, ik heb Ruby and Rails geleerd, RSpec, JavaScript (incl. ES6, JQuery en Ajax), Mocha, Chai, React, SQL en Redux.

Ik heb version control met Github leren gebruiken (verslavend) en heb met ontwikkeld in TDD en Scrum.

Verder lezen Web Developer Certificaat van Codaisseur

Conversie optimalisatie voor ZZP-ers – maak klanten van bezoekers

Conversie optimalisatie is de kunst om klanten te maken van de bezoekers aan je website.

Conversie = hoeveel je verdient per bezoeker

Optimalisatie = zoveel mogelijk verdienen

Als je naïef naar website traffic kijkt, dan is het goed om veel bezoekers te hebben. Maar als die bezoekers niet echt geïnteresseerd zijn in wat jij te bieden hebt, dan heb je er helemaal niets aan om honderden of zelfs duizenden bezoekers per dag te hebben. Ik weet er alles van: zulke sites heb ik.

Dat is niet erg: die websites inspireren en informeren mensen. Ze hebben geen zakelijk doel.

Andere sites hebben in het hoogseizoen honderden bezoekers per dag en leveren dan duizenden euro’s op. Kijk, daar kun je als zakenvrouw mee weg komen. Dat is brood op de plank, hypotheek betaald etc.

Voor een zzp-er is het echter van belang dat je website klanten op levert. Klanten, niet alleen mensen die opbellen om informatie en vervolgens weer verdwijnen.

Als je gaat zoeken op ‘conversie-optimalisatie’ dan vliegen de termen je om je hoofd: A/B testen, usability, web-analytics, neuromarketing…

Dit soort principes werken als je het type bedrijf hebt waar je statistieken op los kunt laten. Voor de meeste zzp-ers zijn ze volkomen irrelevant. Hier mijn factoren voor conversie-optimalisatie voor zzp-ers:

  • Je bent je verhaal
  • Je netwerk is je belangrijkste bron van klanten
  • Wees uitstekend in wat je doet
  • Laat zien wat je in huis hebt
  • Laat zien wat je niet bent

Je bent je verhaal

Of het nu gaat om 50-plussers op de arbeidsmarkt of zzp-ers: de mensen die de draai naar een baan weten te maken zijn degenen die zichzelf helder weten te presenteren.

Als jij niet weet wat je wilt, kan je netwerk je ook niet aan je volgende klus helpen.

Een goede website bouwer weet niet alleen technisch hoe zij een website opzet, maar kan ook helpen je verhaal helder te krijgen.

Je netwerk is je belangrijkste conversie-factor

Als zzp-er moet je het vooral hebben van je netwerk: Mensen die weten wat je kunt en naar je doorverwijzen. Sympathie, de gunfactor.

Je website helpt je zodat je je verhaal niet twintig keer per dag hoeft te vertellen. Dat doet je website al voor je.

Wees uitstekend in wat je doet

Er zijn een heleboel mensen heel behoorlijk in wat ze doen. In loondienst is dat goed genoeg. In loondienst gaat het er om dat je op de juiste stoel zit en het goed genoeg doet om niet ontslagen te worden.

Als zzp-er ga je van klus naar klus. Je moet jezelf elke keer weer verkopen – de meest authentieke manier om dat te doen is door precies te zijn wat je zegt dat je bent. En laat dat ook zien…

Laat zien wat je in huis hebt

Veel Nederlanders hebben de neiging – en de meeste vrouwen nog meer – om verlegen achter een bosje te gaan zitten en vervolgens te verwachten dat mensen opmerken hoe goed je het doet. Dat werkt misschien op school, maar in het echte leven moet je laten zien wat je in huis hebt.

Je website is een van de plekken om dat te doen. En ja, dit is een principe van conversie optimalisatie – laten zien van autoriteit. (*)

Laat zien wat je niet bent

Een effectieve website voor een zzp-er trekt niet alleen klanten. Een duidelijk verhaal zorgt ook dat mensen die NIET bij jou bedrijf passen afdruipen zonder je lastig te vallen.

Hoe help ik daarbij?

Een acceptabele website in elkaar zetten kunnen heel veel mensen. Misschien ben jij er wel een van.

Ik kan je helpen door je verhaal te stroomlijnen, het ontwerp bij je boodschap aan te laten sluiten en de juiste toon te zetten.

Voetnoot

*) De Cialdini-beïnvloedingsprincipes: sociale bewijskracht (via je netwerk), autoriteit, schaarste, consistentie (je duidelijke verhaal), sympathie, wederkerigheid (jij geeft, de ander voelt zich verplicht terug te geven) en verbondenheid (een gezamenlijk doel, ‘ons’).

bol.com affliate programma en nofollow links

Bol.com heeft vorige week geschreven over of je links naar bol.com, via het affiliate programma, moet voorzien van het nofollow attribuut.

Het antwoord dat ze geven (waar ik overigens niet achter sta) is als volgt:

Google heeft aangegeven dat het een voorstander is voor het gebruik van het nofollow attribuut voor betaalde links op een site. Zo kun je aangeven dat de link er staat omdat er voor betaald is door een adverteerder en dat de link daarom geen “stem” is voor die site. Voor jouw eigen website maakt het dus niet uit of je wel of geen no follow link maakt van je partnerlinks. Het zorgt er dus alleen voor dat ‘spamlinks’ niet mee worden geteld voor de ranking in google.

Die eerste zin klopt:

Google heeft aangegeven dat het een voorstander is voor het gebruik van het nofollow attribuut voor betaalde links op een site.

Belangrijk is te weten dat elke affiliate link in de ogen van Google een betaalde link is. En hoewel het advies van Google niet altijd al te letterlijk genomen moet worden, zou ik dat in dit geval wel aanraden.

Dus zet nofollow in je links naar het bol.com affiliate programma.

Dat gaat als volgt:

<a href=”http://www.site.com/page.html” rel=”nofollow” >Visit My Page</a>

of

<a rel=”nofollow” href=”http://www.site.com/page.html” >Visit My Page</a>

Wat gaat er mis als je dit advies van Google niet op volgt?

1) Je loopt kans dat bol.com de traffic krijgt in plaats van jijzelf.

Stel: je schrijft een recensie over het nieuwste boek van A. Grunberg. Dan wil je natuurlijk dat, mochten mensen op zoek zijn naar recensies van dat boek, jou site boven komt drijven in Google. En dan wil je dat ze doorklikken naar bol.com en het boek kopen zodat jij commissie krijgt.

Probleem: zonder nofollow in je link, is de kans groot dat bol.com hoger in de zoekmachine resultaten terecht komt dan jij. Dat was niet helemaal de bedoeling – althans voor jou. Voor bol.com is het natuurlijk fantastisch: ze hoeven jou niet te betalen en krijgen ook nog meer traffic.

2) Als google weet dat er betaalde links op je site staan, loop je groot risico dat je lager in de zoekresultaten gezet wordt, of er zelfs uit geweerd wordt.

Google heeft een groot probleem met links. Aan de ene kant zijn ze essentieel om te bepalen wat goede / belangrijke / interessante inhoud is op het web. Aan de andere kant weten webmasters dit ook en gaan ze er dus naar sturen.

Er is dus de afgelopen 10 jaar een betaalde link economie ontstaan. Links zijn geld waard.

Google straft dit aan twee kanten af. Stel: Site A linkt naar site B en krijgt daarvoor betaald.

  1. Stel, site B heeft overwegend betaalde links naar zich toe, dan kan die site lager in de zoekmachine resultaten terecht komen, of er zelfs uit verbannen worden.
    Bol.com is overigens te groot om met dit effect te maken te krijgen.
  2. Site A heeft zowel betaalde als onbetaalde links. Dan zijn dit de mogelijke gevolgen (als Google er achter komt):
    1. De links op die site kunnen allemaal als niet tellend te boek gaan staan. Dus die ene link naar bol.com kan betekenen dat ook de links naar je vriendjes hen niet helpen om in Google te ranken.
    2. Als de kwaliteit van site A toch al niet zo hoog is, en site A zelf niet al te goede links naar zich toe heeft, dan kan die betaalde link er toe bijdragen dat site A zelf minder goed in de zoekmachines rankt, of zelfs verbannen wordt.

Conclusie

  • Affiliate links zijn betaalde links
  • Google is almachtig
  • Je kunt het je niet veroorloven het risico te lopen dat je site afgestraft wordt, dus kan je beter gewoon nofollow in al je links naar het bol.com affliate netwerk zetten.

Hoe maak je een goede blogpost titel?

Literaire titels voor blogposts – niet doen!

Laat ik beginnen te zeggen dat er op elke regel uitzonderingen zijn. In het geval van creatieve titels voor blogposts is de duidelijke uitzondering: creatieve blogs. Als je een gedicht online zet, is het logisch dat de titel een literaire titel is, namelijk de titel van het gedicht.

Wil je echter met je blog nieuwe lezers aantrekken, of de kans groot maken dat je abonnees de moeite nemen in hun mail door te klikken van de titel naar de inhoud van je blog, dan zul je moeten zorgen dat de titel van je stukje samenvat waar het over gaat.

De beste titels voor blogposts hebben de volgende eigenschappen: Verder lezen Hoe maak je een goede blogpost titel?