I'm using vue 3 and composable files for sharing some functions through my whole app.
My usePluck.js composable file looks like
import { api } from 'boot/axios'
export default function usePlucks() {
const pluckUsers = ({val = null, excludeIds = null}) => api.get('/users/pluck', { params: { search: val, exclude_ids: excludeIds }})
return {
pluckUsers
}
}
In order to make use of this function in my component I do
<script>
import usePlucks from 'composables/usePlucks.js'
export default {
name: 'Test',
setup() {
const { pluckUsers } = usePlucks()
onBeforeMount(() => {
pluckUsers({excludeIds: [props.id]})
})
return {
}
}
}
</script>
So far so good, but now I'd like to even be able to not send any args to the function
onBeforeMount(() => {
pluckUsers()
})
But when I do that, I get
Uncaught TypeError: Cannot read properties of undefined (reading 'val')
I assume it's because I'm not sending an object as argument to the function, therefore I'm trying to read val from a null value: null.val
What I'm looking for is a way to send, none, only one, or all arguments to the function with no need to set null values:
// I don't want this
pluckUsers({})
// Nor this
pluckUsers({val: null, excludeIds: [props.id]})
I just want to send only needed args.
Any advice about any other approach will be appreciated.
import { api } from 'boot/axios'
export default function usePlucks() {
const pluckUsers = ({val = null, excludeIds = null} = {}) => api.get('/users/pluck', { params: { search: val, exclude_ids: excludeIds }})
return {
pluckUsers
}
}
I believe this is what you're looking for. The { ... } = {}
EDIT: It didn't work without this because with no argument the destructuring failed because it can't match an object. That's why you also need a default value on the parameter object, also called simulated named parameter.
Related
How can I pass a variable between plugins in Rollup?
What I've tried:
// plugin-a.js
const pluginA = () => {
return {
name: 'pluginA',
async options(options) {
options.define = options.define || {};
options.define['foo'] = 'bar';
}
}
}
// plugin-b.js
const pluginB = (options = {}) => {
return {
name: 'pluginB',
buildStart: async (options) => {
console.log(options)
}
}
}
I'm getting a warning:
(!) You have passed an unrecognized option
Unknown input options: define. Allowed options: acorn, acornInjectPlugins, cache, context, experimentalCacheExpiry, external, inlineDynamicImports, input, makeAbsoluteExternalsRelative, manualChunks, maxParallelFileOps, maxParallelFileReads, moduleContext, onwarn, perf, plugins, preserveEntrySignatures, preserveModules, preserveSymlinks, shimMissingExports, strictDeprecations, treeshake, watch
It seems passing data should be done by what Rollup refers to as Direct plugin communication. This is working for me. I feel this is very hard coupled though.
function parentPlugin() {
return {
name: 'parent',
api: {
//...methods and properties exposed for other plugins
doSomething(...args) {
// do something interesting
}
}
// ...plugin hooks
};
}
function dependentPlugin() {
let parentApi;
return {
name: 'dependent',
buildStart({ plugins }) {
const parentName = 'parent';
const parentPlugin = plugins.find(plugin => plugin.name === parentName);
if (!parentPlugin) {
// or handle this silently if it is optional
throw new Error(`This plugin depends on the "${parentName}" plugin.`);
}
// now you can access the API methods in subsequent hooks
parentApi = parentPlugin.api;
},
transform(code, id) {
if (thereIsAReasonToDoSomething(id)) {
parentApi.doSomething(id);
}
}
};
}
There's also Custom module meta-data, however when I read the meta I always get null.
I am having problems in an html tag that uses an object from my object in store.
When i refresh my page, the array from my sotre is empty, so i when i refresh in the index page, it will first load the html, then the mounted method, and its where i fill my store. its says that Cannot read property 'substring' of undefined
index.vue that i use this object:
<p v-html="pegaPrimeiroPost.conteudo.substring(0,500)"></p>
export default of index.vue:
computed: {
...mapGetters({
postsDB: "postagensDB/pegaPosts",
pegaPrimeiroPost: "postagensDB/pegaPrimeiroPost",
}),
},
methods: {
...mapActions({
buscaPostDB: "postagensDB/pegaPostsDB",
}),
},
async mounted() {
**await this.buscaPostDB();**
});
},
this object pegaPrimeiroPost is an objetct from my array that i fill from my database.
store/postagensDB:
import axios from 'axios'
export const state = () => ({
posts: [],
primeiroPost: {},
})
export const getters = {
pegaPosts(state) {
return state.posts;
},
pegaPrimeiroPost(state) {
return state.primeiroPost;
},
}
export const actions = {
async pegaPostsDB(state) {
await axios
.get("http:/MY_API_ADRESS")
.then((response) => {
state.commit('carregaStatePosts', response.data)
})
.catch((response) => {
console.log(response)
});
},
}
export const mutations = {
async carregaStatePosts(state, postsDB) {
state.posts = postsDB.posts;
state.primeiroPost = state.posts[0];
},
}
If i erase the substring() method, reload the page, then it will fill my store; and then re-add the substring(), it works, but wont solve my prob. Can anyone help me?
I've never used Vue, but this sounds like you have some sort of async action that populates the object, but your default value (used before the async call has completed) doesn't have that property. The quickest solution is probably just give it a value if it doesn't exist:
(pegaPrimeiroPost.conteudo || '').substring(0,500)
or set a "default" object with that property:
export const state = () => ({
posts: [],
primeiroPost: { conteudo: '' },
})
I'm trying to create a custom hook function that uses useCallback
function. Here's a toy example:
export function useCustomLink(link: { url: string; description: string }) {
const [updating, setUpdating] = useState<boolean>(false);
const [linkInfo, setLinkInfo] = useState<{ url: string; description: string } | "loading" | "error">("loading");
useEffect(() => {
// initiate linkInfo
if (!updating) {
setLinkInfo(link);
}
}, [link]);
const updateLink = useCallback((update: Partial<{ url: string; description: string }>) => {
if (linkInfo !== 'loading' && linkInfo !== 'error') {
const updated = { ...linkInfo, ...update };
setLinkInfo(updated);
setUpdating(true);
}
}, [linkInfo, link]);
return {
linkInfo, updateLink
};
}
My understanding of the dependency list is that I only need to add variables that are directly used by the function (in this case, linkInfo). However, if I don't add link (which is passed into the custom hook function) into the list as well, then I would end up with stale states of linkInfo. Can anyone help explain why I need to add the add'l variable into the dependencies? Is this the correct way to use useCallback?
Thanks!
In Vue I see code like:
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
and
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
Where the syntax [SOME_MUTATION] (state) comes from? Is [SOME_MUTATION, ANOTHER] (state) also valid syntax? Why SOME_MUTATION (state) (which is valid function syntax) is not used?
How in large Vue project, putting all export const SOME_MUTATION = 'SOME_MUTATION' defintions in separate file really help instead of putting in same file (store.js) ?
In this line
import { SOME_MUTATION } from './mutation-types'
where you are importing the types into SOME_MUTATION, it has a string value. Now to define a function with this name inside an object you need to do
{
[SOME_MUTATION](state) {
}
}
Would be same as (if SOME_MUTATION has a value say changeState)
{
changeState: function(state){
}
}
And state is by default passed as an argument in mutations.
Read more here
We prefer this type of architecture in a Vue application so as to avoid name conflicts in defining Mutations and Actions and Getters across multiple components.
It's a javascript syntax for defining an object key programatically/dynamically.
for example, you have a variable:
var myFunctionName = "getUsers";
you can actually create a function inside an object using the value of a variable as the function name.
So for example,
{
[myFunctionName]() {
// do something
}
}
will actually become:
ES6:
{
getUsers() {
// do something
}
}
or ES5:
{
getUsers: function() {
// do something
}
}
This is not limited to creating functions within an object, but it can be applied to any property within your object.
For example:
let myPropertyName = 'user';
{
[myPropertyName]: {
name: 'Hello',
age: 10
}
}
will become:
{
user: {
name: 'Hello',
age: 10
}
}
Where do you correctly place local functions in vue 2.x?
I could just place them in the "methods" object, but I'd like them to be completely local to the instance if thats possible.
Sort of like this in Plain JS :
window._global = (function () {
function _secretInsideFunct(){
return "FooBar";
}
var __localObject = {
outsideFunct : function () {
return _secretInsideFunct();
}
}
return __localObject;
}());
..where _global._secretInsideFunct() wouldnt be accessible anywhere else but from inside the _global object.
In this specific case I want to make a function that creates an array object if it doesn't exist.. Something like:
function CreateOrSet (workArray, itemName, itemValue ){
var salaryRow = self.Status.Rows.find(r => r.recordID == itemName);
if (!salaryRow) {
salaryRow = { recordID: itemName, recordAmount: 0, recordName: "Løn" };
self.Status.Rows.push(salaryRow);
}
salaryRow.recordAmount = itemValue ;
}
..but a general approach for these cases is better :)
Now this function doesn't looks like a utility or helper function, but relate to a state, Status.Rows. If I were you, I will define it as close as to the state or the module that the state being used.
If the state will be used across the app, maybe I will define it in entry file, index.js or app.vue.
Or If you are using vuex, you can define it as an vuex action. So you may do something like this:
const store = new Vuex.Store({
state: {
status: {
rows: []
},
mutations: {
pushRow (state, salaryRow) {
state.status.rows.push(salaryRow)
},
changeAmount (state, id, amount) {
const salaryRow = state.status.Rows.find(r => r.recordID === id)
salaryRow.recordAmount = amount
}
},
actions: {
createRow (context, itemName) {
const salaryRow = { recordID: itemName, recordAmount: 0, recordName: "Løn" };
context.commit('pushRow', salaryRow)
}
}
})
You can put all of the code to a single action, it is just an idea, how you organize your code depend on your needs.