Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject/Provide is not reactive #7017

Closed
ralphchristianeclipse opened this issue Nov 7, 2017 · 14 comments
Closed

Inject/Provide is not reactive #7017

ralphchristianeclipse opened this issue Nov 7, 2017 · 14 comments

Comments

@ralphchristianeclipse
Copy link

Version

2.5.3

Reproduction link

https://codesandbox.io/s/7o2qp4l3z6

Steps to reproduce

Parent Component

    provide() {
      let reactive = {};

      Object.defineProperties(reactive, {
        challenge: {
          get: () => this.challenge
        }
      });

      return reactive;
    },

Child Component

inject: ["challenge"]

What is expected?

The challenge property should change when its parent this.challenge changes on the proxy

What is actually happening?

Not changing at all


The link provided is just an example how to reimplement what i'm really doing but that is the same code that i use

any ideas?

@posva
Copy link
Member

posva commented Nov 7, 2017

Unfortunately, that's by design. you can hack around it using an object an referring to its children, but it's not recommended because it could break in future versions of Vue

@posva posva closed this as completed Nov 7, 2017
@lehni
Copy link

lehni commented Apr 8, 2019

I'd like to point out two possible solutions to this problem:

  1. There is a plugin/mixin now by @LinusBorg to deal with this: https://github.com/LinusBorg/vue-reactive-provide
  2. Instead of providing the actual computed property, you could provide a method that is to be used as a getter by the children that inject it to then get the property when needed:
// parent:
{
  provide() {
    return {
      $computedProperty: () => this.computedProperty
    }
  },

  computed: {
    computedProperty() {
      // Returns the result of some potentially reactive computation
    }
  }
}

// children:
{
  inject: [
    '$computedProperty'
  ],

  computed: {
    computedProperty() {
      return this.$computedProperty()
    }
  }
}

@LinusBorg
Copy link
Member

That second trick is great, never thought of that!

@lehni
Copy link

lehni commented Apr 8, 2019

@LinusBorg a function used as a tunnel / wormhole through the non-reactive JS space-continuum :)

@Tofandel
Copy link

Tofandel commented Jul 31, 2019

@lehni
Just a small mistake, this is not accessible within the provide object you need to declare it like this for it to work

provide() {
    return {
        $computedProperty: () => this.computedProperty,
    };
  },

@lehni
Copy link

lehni commented Jul 31, 2019

@Tofandel hmmm but you have the same code there as I do? And I'm using this in production, sure works for me...

@lehni
Copy link

lehni commented Aug 1, 2019

@Tofandel never mind, I just noticed now that @posva edited my code to include your fix before I saw your post. I also have this version in my own use, not sure why I posted the object version above initially :)

@Tofandel
Copy link

Tofandel commented Aug 3, 2019

@lehni Haha okay I thought you edited it so I was confused :p

@dmitry
Copy link

dmitry commented Sep 2, 2019

This must be added to the recipes or guides.

@cihad
Copy link

cihad commented Dec 4, 2019

I have discovered new way:

// parent:
{
  provide() {
    const _this = this;
   
    return {
      get computedProperty () {
         return _this.computedProperty;
      }
    }
  },

  computed: {
    computedProperty() {
      // Returns the result of some potentially reactive computation
    }
  }
}

// children:
{
  inject: [
    'computedProperty'
  ],
}

You don't need computed method in children anymore.

@louisameline
Copy link

I discovered a flaw in @lehni 's trick today. Wrapping the object in a function triggers an error when the providing object gets unmounted I think, as if the injection briefly couldn't be resolved anymore:

[Vue warn]: Injection "$computedProperty" not found

This error doesn't happen when a plain object is passed.
I could circumvent it by providing a wrapped-wrapped (!) default value in the child component:

// children:
{
  inject: [
    '$computedProperty': {
      // you need to provide a default object that doesn't trigger errors
      // in your component when used
      default: () => () => {}
    }
  ],
  computed: {
    computedProperty() {
      return this.$computedProperty()
    }
  }
}

It feels dirty overall. We should probably avoid passing functions.
As a reminder, the Vue docs advise against inject/provide anyway, and just use props, even if it's more verbose.

@cihad I haven't been able to make your trick work, it's not reactive for me. And I needed two different names to avoid a loop: get computedProperty () { return _this.$computedProperty }

@sstern6
Copy link

sstern6 commented May 11, 2020

It seems like the only way to get it to work is by providing a function, and then in the component it is injected in you need to create a computed prop and call the function like the example above.

Has there been any progress on opinions of how to tackle this? I dont want to prop drill or use state management. Provide/Inject seems like the best solution, but feels weird we need to hack around the cleanest solution.

Thoughts?

@adamsol
Copy link

adamsol commented Jul 25, 2021

In case anyone is interested, I've built a plugin that implements a simple API for reactive provide/inject basing on @lehni's trick: https://github.com/adamsol/vue-component-store.

@anthonygore
Copy link

You can inject reactive variables with the composition API

setup() {
  const { myVar } = inject(myKey);
  return { myVar } // is reactive assuming myVar is a ref/computed
},
inject: {
  injected: { from: myKey } // injected.myVar is not reactive
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests