Trying to get a value from a custom store Svelte - javascript

i want to ask something, i have a custom store like
const BlaBla = (Data) => {
const { subscribe, set, update } = writable(Data);
return {
subscribe,
update,
set,
setData: (NewData) => {
set(NewData)
},
getData: () => {
return <<<<<<< "Here lies the problem, how i can get the "newData"?."
}
}
}
i will explaying the scenario, im creating a script for a fivem server and im using svelte, i create a store that get a Vehicle with some properties like Name, Last Name, Plate and bla bla, i create the setData(Vehicle) and pass a set(Vehicle) then in another method i want to "get" the plate only, one solution i did was creating a variable in the scope and instead of a set i did an update like this
const VehicleStore = (Vehicle) => {
let Data = {} //Variable inside the scope
const { subscribe, set, update } = writable(Vehicle);
return {
subscribe,
update,
set,
setData: (NewData) => {
update((s) => {
s = NewData
Data = s
return s
})
},
getData: () => {
return Data.Plate
}
}
}
i don't know if this is the actual solution, i think im missing something

Svelte exports a get function that can be used to resolve the value of a store once (it is syntactic sugar around subscribe).
So first you have to get the value of the store, then you can access its property:
import { get } from 'svelte/store';
// ...
const store = writable(Data);
const { subscribe, set, update } = store;
// ...
return get(store).Plate
Note that accessing data like this will not be reactive because there is no persistent subscription to the store. You are generally not meant to use stores like that.
Instead you usually would use the store in a component's markup using auto subscriptions via $:
$VehicleStore.Plate

Related

Attempted to assign to readonly property

first of all i get my redux array then in my_function copy that into new variable like below :
let transactions_list = useSelector(state => state.transactions_list.value);
let new_transactions_list = [...transactions_list];
when i want to change my new_transactions_list very deeply i got the error
const my_function = () => {
let new_transactions_list = [...transactions_list];
new_transactions_list[yearIndex].data_yearly[monthIndex].data_monthly.push(new_obj);
}
but when i define an array in class(without redux), it's work
Even if you are using the spreading [...transactions_list], you are still only copying the first level of the array, which means that the object below that array is still the same one that redux uses.
You have 2 options:
This is how redux recommends you to update nested object link
function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
Or you can use something like immer, which will allow you to update your object even with immutable like this
const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})
Either way, you will have to update your redux state afterward since this change will only be local in your code and not the global redux.

Passing Reactive State from Vuex to Composable

I'm working on a composable that's meant to encapsulate some logic with Vue3 and Vuex. The composable is working with a "feed" that is liable to change in the future, and comes from Vuex.
I'd like the composable to return the status of that feed when the feed changes as a computed value.
However, I'm unclear on how to fetch/wrap the value from Vuex so this computed property will change when the value in Vuex changes. For instance, at the top of the composable, I'm passing in the ID of the feed, fetching it from Vuex, and then using it in the composable like this:
const feed = store.getters['feeds/getFeedById'](feedId)
I'm then using the feed in a computed, inside of the composable, like this:
const feedIsReady = computed(() => feed.info.ready ? 'READY' : 'NOT READY')
However, when I change the feed object in Vuex via a mutation elsewhere in the application, the feed inside the composable does not change.
I've tried wrapping the feed in a reactive call and it's individual properties with toRefs but those approaches only provide reactivity within the composable itself, and don't capture changes from Vuex.
How would one wrap the feed from Vuex to provide reactivity? I need the changes in Vuex to propagate to my composable somehow.
Did you try to use vuex getter in your composable with computed property:
const feed = computed(() => store.getters['feeds/getFeedById'](feedId));
I see you are using store.getters['feeds/getFeedById'](feedId), which, AFAICT, means that the getter store.getters['feeds/getFeedById'] returns a function, and that the feedId is a parameter passed to the returned function.
If this is the case, this probably won't work, because that function likely doesn't return a reactive value.
I can't see the vuex code so don't know for sure, but assuming this is the case I would do something like this
const store = Vuex.createStore({
state() {
return {
feeds: {
1334:{info:{ready:false}},
}
}
},
getters: {
feeds(state) {
return state.feeds
}
},
mutations: {
change(state) {
state.feeds[1334].info.ready = !state.feeds[1334].info.ready;
}
}
});
function watchFeedState(feedid) {
const feeds = Vue.computed(() => store.getters.feeds)
const isReady = (v) => v && v.info && v.info.ready ? 'READY' : 'NOT READY';
const feedReady = Vue.ref(isReady(feeds[feedid]));
Vue.watch(store.getters.feeds, (v) => {
feedReady.value = isReady(v[feedid])
});
return feedReady
}
const app = Vue.createApp({
setup() {
const store = Vuex.useStore();
const isReady = watchFeedState(1334); // <= the feed from a higher order function
return {
isReady,
change: ()=>{store.commit('change')}
}
}
});
app.use(store);
app.mount("#app");
<script src="https://unpkg.com/vue#3.2.37/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vuex#4.0.0/dist/vuex.global.js"></script>
<div id="app">
<button #click="change">toggle state</button>
{{ isReady }}
</div>
This creates a higher order function to watch a specific feed id. This will watch the feeds getter for every change, but only update for a provided feedid.

My mapStateToProps is not called after adding custom object array to redux state

I am trying for few hours but can't figure out why my state is not called after adding an array of custom object.
// In my component...
const myRemoteArray = getRemoteArray() // Is working
props.addAdItems(myRemoteArray) // Calls **1 via component.props
/// ...
const mapDispatchToProps = (dispatch) => {
return {
addAdItems: (items) => { // **1
// Items contains my array of objects
dispatch(addAdItems(items)) // Calls **2
},
}
}
// My action
export const addAdItems = (items) => { // **2
// Items contains my array of objects
return { // Calls **3
type: AD_ITEMS,
adItems: items,
}
}
const productsReducer = (state = initialState, action) => {
switch (action.type) { // **3
case AD_ITEMS:
// Is working!
// action.adItems contains my array!
const _state = {
...state,
adItems: action.adItems, // Here is the issue, I am not sure how to add my NEW array to existing state and update it.
// Like that: ??? "adItems: ...action.adItems" or adItems: [action.adItems]
}
// The new state contains my Array!!!
return _state
default:
return state
}
}
// In my component... !!!!
// THIS IS NOT CALLED or it is called with empty array from initialState!!!
const mapStateToProps = (state) => {
return {
updatedItem: state.changedItem,
adItems: state.adItems,
}
}
It seems to me that Redux is having a problem with my array containing the following data. Has Redux issues with my class methods?
class Ad {
constructor(
id,
isPublished
) {
this.id = id
this.isPublished = isPublished
}
someMessage = () => { return "Help me!" }
needHelp = () => { return true }
}
My Redux is working already with other calls, data, and objects, which means my createStore and all other stuff is correct.
PS: I don't have multiple stores.
UPDATE
Now my mapDispatchToProps is called with current array but is not persisting.
UPDATE 2
If I save my file and force to refresh the App, the props.adItems contains my loaded array, but if I want to access props.adItems at runtime (e.g. on FlatList refresh) it is empty array again!
Why?
Should I store my array in a useState property after it has changes via useEffect?
You were pretty close in the comments you added in the reducer, but neither of them were 100% accurate.
For Redux to notice that your array has changed, you need the property adItems of your new state to return an entirely new array. You can do it like this:
adItems: [...action.adItems]
With this code you'll be creating a new array, and then adding a copy of the items of the old one into it.
The reason why your current implementation (adItems: action.adItems) is not working is that action.adItems is actually a reference to an array in memory. Even though the array contents have changed, the value of action.adItems is still the same, a pointer to where the array is currently stored. This is the reason why your store is not being updated: as Redux does not check the values of the array itself but the reference to where the array is stored, the new state you're returning is exactly the same, so Redux is not aware of any changes.
As LonelyPrincess says, I was making this issue elsewhere, if you doing that xArray = yArra it means call by reference and not by value.

Add Vue.js computed property to data gathered from a server

Coming from Knockout.js, where you can simply create an observable everywhere by defining it, is there something similar in Vue.js?
let vm = {
someOtherVar: ko.observable(7),
entries: ko.observableArray()
};
function addServerDataToEntries(data) {
data.myComputed = ko.pureComputed(() => vm.someOtherVar() + data.bla);
vm.entries.push(data);
}
addServerDataToEntries({ bla: 1 });
In my Vue.js project, I'm getting a list of objects from the server. For each of those objects, I want to add a computed property that I can use in a v-if binding. How can I achieve that?
I'm not familiar with the way Knockout does it but it sounds like a Vue computed. Create a data object to hold your fetched data:
data() {
return {
items: null
}
}
Imagine fetching it in the created hook (or Vuex, wherever):
async created() {
const response = await axios.get(...);
this.items = response.data;
}
Create your computed:
computed: {
itemsFormatted() {
if (!this.items) return null;
return this.items.map(item => {
// Do whatever you want with the items
});
}
}
Here is a demo using this pattern where I'm loading some data and printing out a filtered result from it. Let me know if I misunderstood what you're looking for. (You can see the original fetched data in the console.)

want to show updated status value in another component

i want to watch when a mutation called and updated a status. i make a component to show database table count when api called.
this is my store i wrote
const state = {
opportunity: ""
}
const getters = {
countOpportunity: state => state.opportunity
}
const actions = {
// count opportunity
async totalOpportunity({ commit }) {
const response = await axios.get(count_opportunity)
commit("setOpportunity", response.data)
},
}
const mutations = {
setOpportunity: (state, value) => (state.opportunity = value)
}
i want to show this getter value when this mutation called in another component name Opportunity.vue file.
i showed database count values in file name Dashboard.vue
i wrote it like this.
computed: {
...mapGetters(["countOpportunity"])
},
watch: {},
mounted() {
//do something after mounting vue instance
this.$store.watch(() => {
this.$store.getters.countOpportunity;
});
},
created() {
this.totalOpportunity();
},
methods: {
...mapActions(["totalOpportunity"])
}
and showed my view like this.
<div class="inner">
<h3>{{ countOpportunity }}</h3>
<p>Opportunities</p>
</div>
when api called and count increase shows my mutations. but my view value not updated (countOpportunity). any one can help me to fix this.
The issue here (most likely) is that the value of response.data is an object or an array. You've initially defined opportunity as '' which is not an observable object or array. You have 2 choices:
Redefine it as an empty object or array, depending on the response:
opportunity: [] // or {}
Otherwise, use Vue.set() to apply reactivity when changing it:
(Vue.set(state, 'opportunity', value))

Categories

Resources