alanbuchanan
alanbuchanan

Reputation: 4173

Ensure multiple instances of the same component have non-shared state

I have an app in which I have a counter which shows a value, and a button that can increment that value.

I used simple state management from scratch as the docs suggest.

I can add counters to this list with an 'Add Counter' button so that I have multiple counters on the page.

Despite each instance of my counter component having a separate key in the parent component (as per the docs), each instance of the counter shares the same value:

counters-with-shared-state

How can I add a separate instance of the same component that has its own state?

Here is the code on webpackbin: http://www.webpackbin.com/41hjaNLXM

Code:

App.vue

<template>
  <div id="app">
    <counter v-for="n in state.countersAmount" :key="n"></counter>
    <button v-on:click="addCounter">Add a Counter</button>
  </div>
</template>

<script>
  import Counter from './Counter.vue'

  const store = {
    state: {
      countersAmount: 1
    },
    incrementCounters() {
      ++this.state.countersAmount
    }
  }

  export default {
    data() {
      return {
        state: store.state
      }
    },
    methods: {
      addCounter() {
        store.incrementCounters()
      }
    },
    components: {
      Counter
    }
  }
</script>

Counter.vue

<template>
    <div>
        <h1>{{state.counterValue}}</h1>
        <button v-on:click="increment">+</button>
    </div>
</template>
<script>
const store = {
    state: {
        counterValue: 0,
    },
    increment() {
        ++this.state.counterValue
    }
}
export default {
    data() {
        return {
            state: store.state
        }
    },
    methods: {
        increment() {
            store.increment()
        }
    }
}
</script>

Upvotes: 2

Views: 4285

Answers (2)

Tiago Engel
Tiago Engel

Reputation: 3661

You're using the same state for every Counter instance.

const store = {
  state: {
    counterValue: 0,
  },
  increment() {
    ++this.state.counterValue
  }
}

The code above will be executed only once, and every instance of this component will share this state.

To change this, just return a new object as the initial state, like so:

<template>
    <div>
        <h1>{{counterValue}}</h1>
        <button v-on:click="increment">+</button>
    </div>
</template>
<script>

export default {
    data() {
        return {
          counterValue: 0
        }
    },
    methods: {
        increment() {            
            ++this.counterValue;
        }
    }
}
</script>

The Simple State Management from Scratch you linked, is for shared state between components, as you can see in the picture:

enter image description here

Upvotes: 2

Mati
Mati

Reputation: 1148

You are always returning the same instance of the component. Instead, you should return a new instance.

Upvotes: -1

Related Questions