Watching page (month) change - vue.js

I'm using the Day Grid Month, how can I attach an event listener to trigger whenever I change the current page (month)? I tried using a watcher but didn't work
mounted () {
const api = this.$refs.fullCalendar.getApi()
this.$watch(
() => api.currentData.dateProfile.currentRange.start,
newValue => console.log(newValue),
{ deep: true }
)
}

Related

Why this navigation.goBack is not working as I intended ? How can I get the Last Active State?

I got 3 pages
homepage, productList and productDetails
When going from homepage to productList I pass a route param,
navigation.navigate('productList', { showCategory: 'productListA'} )
InitialProcess when component mounted
Inside the productList page when the component is mounted. I am declaring use state like this.
const {showCateory} = route.params;
const [activeTab, setActiveTab] = useState(showCateory);
and calling api using that activeTab
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
activeTab,
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, []);
User Interaction
But I also add the button in the productList so that user can change the current active tab
<TouchableOpacity onPress={() => changeTab()}></TouchableOpacity>
const changeTab = async () => {
await setActiveTab('productListB'),
await dispatch(fetchProductList(activeTab)
}
Take note that right now active tab and data coming from api is different from when the component is start mounted.
Navigation Change again
When use goes from productList to productDetails. All thing is fine.
But inside the product details I am going back to productList with this.
navigation.goBack().
When I am back in productList page The activeTab is change back to productListA and the data is change back to when component is mounted
Can I pass or change the route params when calling navigation.goBack()?
add activeTab in useEffect depedineces.
as docs say
The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that’s what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically.
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
//this value will always updated when activeTab change
activeTab,
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, [activeTab]); //<<<<< here
also you need to know setState() does not always immediately update the component. see here
so change this
const changeTab = async () => {
//await setActiveTab('productListB'),
//await dispatch(fetchProductList(activeTab)
setActiveTab('productListB')
dispatch(fetchProductList('productListB'))
}
This might be happening because route.params is still set to { showCategory: 'productListA'} when you are coming back to the screen.
If this is the case, you can fix it by Changing params object in changeTab() like
navigation.setParams({
showCategory: 'productListB',
});
I hope this will fix your problem.
This happens because the callback function inside the focus listener uses the initial value of the state when the function was defined (at initial page render) . Throughout the lifespan of listener the callback function uses this stale state value.You can read more about this behaviour in this answer
Although the answer by Ahmed Gaber works in this case as the listener is cleared and redefined after each state change.Another common work-around is to use an useRef instead of useEffect.A ref is basically a recipe that provides a mutable object that can be passed by reference.
In your case you can initialise activeTab with navigation param value using useRef hook as :
const activeTab = useRef(showCateory);
and the focus listener callback function should be changed to use the Reference current value as
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
activeTab.current, //<<<<<<---------here
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, []);
and the changeTab function can directly update reference current value
const changeTab = async () => {
setActiveTab.current = 'productListB';
dispatch(fetchProductList('productListB'))
}

Difference in watch properties vs $watch method in created event (Vue)

Is there any difference in watch properties vs $watch method in Vue? For example, I'm trying to understand why the Author use the $watch event instead of watch property in the code below.
created () {
const routes = this.mainMenu.find(item => item.path === '/')
this.menus = (routes && routes.children) || []
// 处理侧栏收起状态
this.$watch('collapsed', () => {
this.$store.commit(SIDEBAR_TYPE, this.collapsed)
})
this.$watch('isMobile', () => {
this.$store.commit(TOGGLE_MOBILE_TYPE, this.isMobile)
})
},
If say I move the $watch as below, is there any difference?
watch: {
isMobile : function(value) {
this.$store.commit(TOGGLE_MOBILE_TYPE, value)
},
collapsed : function(value) {
this.$store.commit(SIDEBAR_TYPE, value)
}
},
created () {
}
Please advise.
The watch options uses this.$watch method under the hood, so it's basically the same.
The only difference is that this.$watch returns a function you can call to stop the watcher:
const queryWatcher = this.$watch('$route.query', doSomethingFunction)
...
queryWatcher() // Stop the watcher
There's no point of using this.$watch is you don't need that stop function so you can safely move them to the watch option property.

How to call function when update state and after DOM full loaded

I want when update state and after DOM full loaded, I will use js to update CSS. So now, I'm using document ready function in the method. Is there any writing style in Vuex? How can I write them in mounted?
computed: {
...mapGetters([
'wsInfo'
])
},
mounted () {
??????
},
method: {
moveWs (from, to) {
//update state
this.wsInfo.workspaces.splice(to, 0, this.wsInfo.workspaces.splice(from, 1)[0])
$(document).ready(function () {
// code run after update state and dom loaded
})
}
}
You need to use a nextTick Function.
Also you can use it inside a method vuejs object.
You can read more about it here:
https://v2.vuejs.org/v2/api/#vm-nextTick
new Vue({
// ...
methods: {
// ...
example: function () {
// modify data
this.message = 'changed'
// DOM is not updated yet
this.$nextTick(function () {
// DOM is now updated
// `this` is bound to the current instance
this.doSomethingElse()
})
}
}
})

How to remount a screen from another screen? (Refresh the whole app again with new parameters)

I have a configurable application which everything is fed into the app from a middleware (like colors and contents) based on a unique id so-called appId.
In the home screen, I am fetching all required data from a middleware in componentDidMount() function and then use it later on. For the first time, I am using a default appId and the componentDidMount() looks like this:
componentDidMount() {
this.setState({ isLoading: true });
fetch(
API +
"configurations" +
"?" +
"uuid=blabla" +
"&" +
"appId=" +
appId +
"&" +
"locale=" +
locale +
"&" +
"gid=" +
gid,
{
method: "GET",
headers: {
Accept: "application/json"
}
}
)}
I have another screen (settings screen) where I have a box and the user can insert appId as input.
When the appId is inserted by the user (in the settings page), I would like to navigate back to the Home screen and re-fetch the data with the new appId that was inserted by the user. The setting screen looks like this:
state = {
newappId: "" };
handlenewappId = text => {
this.setState({ newappId: text });
};
.....
<Item regular>
<Input
onChangeText={this.handlenewappId}
placeholder="Regular Textbox"
/>
<Button
onPress={() => {
navigation.navigate("Home");
}}
>
<Text>Save</Text>
</Button>
</Item>
However, when I do navigation.navigate("Home") the componentDidMount() is not triggered in order to fetch the data again from the middleware (which is expected since it is only triggered for the first time).
What should I do? What is the solution?
I have already tried the solution given in `componentDidMount()` function is not called after navigation
but it didn't work for me.
also tried to move the code in componentDidMount() into a separate function and call it from the settings page but I couldn't make it work.
============== UPDATE: ==============
I was able to solve the issue with the answer given by "vitosorriso" below. However, a new issue occurs. After fetching is done, I am pushing the response to the state and then use it my home screen like this:
fetchData = async () => {
this.setState({ isLoading: true }, async () => {
//fetch the data and push the response to state. e.g:
this.setState({ page: data, configs: data2, isLoading: false });
}}
....
render() {
const { configs, page, isLoading, error } = this.state; //getting the data fetched in the fetch function and pushed to the state
if (isLoading || !page || !configs) {
//if data is not ready yet
);
// Use the data to extract some information
let itemMap = page.item.reduce((acc, item) => {
acc[item.id] = item;
item.attributes = item.attributes.reduce((acc, item) => {
acc[item.key] = item.value;
return acc;
}, {});
return acc;
}, {});
}}
For the first time the app starts, everything works fine and there is no error but if I go to the settings page and press the button to navigate back to the home screen and fetch data again, I face the error:
"items.attributes.reduce is not a function".
I am assuming the reason is, "items.attributes" already has a value (from the first time) and can't fed with new data again.
Is there any way, to clear all the variables when navigating from settings page to the home page?
I have solved the same problem in my app with a similar concept of this ( `componentDidMount()` function is not called after navigation ) but using a different syntax, and it is working for me:
// your home class
// no need to import anything more
// define a separate function to fetch data
fetchData = async () => {
this.setState({ isLoading: true }, async () => {
// fetch your data here, do not forget to set isLoading to false
}
}
// add a focus listener onDidMount
async componentDidMount () {
this.focusListener = this.props.navigation.addListener('didFocus', async () => {
try {
await this.fetchData() // function defined above
} catch (error) {
// handle errors here
}
})
}
// and don't forget to remove the listener
componentWillUnmount () {
this.focusListener.remove()
}

How to send data from one Electron window to another with ipcRenderer using vuejs?

I have in one component this:
openNewWindow() {
let child = new BrowserWindow({
modal: true,
show: false,
});
child.loadURL('http://localhost:9080/#/call/' + this.chatEntityId + '?devices=' + JSON.stringify(data));
child.on('close', function () { child = null; });
child.once('ready-to-show', () => {
child.show();
});
child.webContents.on('did-finish-load', () => {
console.log("done loading");
ipcRenderer.send('chanel', "data");
});
}
And then in child window component:
mounted() {
ipc.on('chanel', (event, message) => {
console.log(message);
console.log(event);
});
}
I tried that .on in created() and beforeCreate() and with this.$nextTick(), withsetTimeout` but nothing works.
I don't want to send some string data but object but as you can see not event simple string "data" works. I am out of ideas.
I can see that this only works in parent component for component where that emit came from if i do this:
send
listen in main process
send back to event.sender
So, question is how to pass any form of data from one window to another?
Ok, after long night, morning after solution.
In some vuejs componenet some action on button click for example
ipcRenderer.send('chanel', someData);
In main process
ipcMain.on('chanel', (event, arg) => {
let child = new BrowserWindow()
// other stuff here
child.loadURL(arg.url)
child.on('show', () => {
console.log("done loading");
child.webContents.send('data', arg);
});
})
In vuejs component for other route arg.url
mounted() {
ipc.on('chanel', (event, message) => {
console.log(message);
console.log(event);
});
}