N
Nuxt2mo ago
sirlav0ie

State not changing when using a composables

Hello, my component was not updating when I changed player id using a composables when I placed this directly in component it was working but as composables it wasn't: import { ref, computed } from 'vue'; import { throws } from '~/data/baseball'; export function usePlayerData(players, playerId) { const selectedPlayer = computed(() => { if (playerId === null) { return null; } return players.find((player) => player.id == playerId); }); const selectedThrows = computed(() => { if (selectedPlayer.value === null) { return null; } return throws.filter((shot) => shot.player_id === selectedPlayer.value.id); }); return { selectedPlayer, selectedThrows }; } So this is now my composables and in my component: const props = defineProps({ playerId: { required: true, }, }); const { value: players } = useState('players'); const { selectedPlayer, selectedThrows } = usePlayerData( players, props.playerId ); This was not working anyone knows why? This works tho: Composables: import { ref, computed } from 'vue'; import { throws } from '~/data/baseball'; export function usePlayerData(players, playerId) { const selectedPlayer = computed(() => { if (playerId.value === null) { return null; } return players.find((player) => player.id == playerId.value); }); const selectedThrows = computed(() => { if (selectedPlayer.value === null) { return null; } return throws.filter((shot) => shot.player_id === selectedPlayer.value.id); }); return { selectedPlayer, selectedThrows }; } Component: const props = defineProps({ playerId: { required: true, }, }); const reactivePlayerId = ref(props.playerId); watch( () => props.playerId, (newPlayerId) => { reactivePlayerId.value = newPlayerId; } ); const { selectedPlayer, selectedThrows } = usePlayerData( players, reactivePlayerId ); I used a watch for my ref
9 Replies
sirlav0ie
sirlav0ie2mo ago
Does anyone can explain why the old one does not work and why the new one works and if there is a better way to do so
Reinier Kaper
Reinier Kaper2mo ago
You don't have to use a ref at all. Props are already reactive, just use props.playerId where you need it
sirlav0ie
sirlav0ie2mo ago
does not work, as I showed in the first solution
const props = defineProps({
playerId: {
required: true,
},
});

const { value: players } = useState('players');

const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
);
const props = defineProps({
playerId: {
required: true,
},
});

const { value: players } = useState('players');

const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
);
Reinier Kaper
Reinier Kaper2mo ago
Your code in the post is hard to read because it's all just text. What is it you're trying to achieve? And does it also not work in a reproduction? I don't see why a reactive prop wouldn't work
Lannister
Lannister2mo ago
would be better to format that code 🙂
Mähh
Mähh2mo ago
Wait, even if props are reactive, not every value in props is reactive. So if you pass props.playerId to a composable, the value of it within the composable is not reactive anymore. If props.playerId change within the component, the composable still keeps the old value, so the watcher in your composable:
export default (playerId) => {
watch(() => playerId, {
console.log('playerId changed')
})
}
export default (playerId) => {
watch(() => playerId, {
console.log('playerId changed')
})
}
will not trigger, since only the props is reactive, not the props.playerId itself. So if you pass const foo = myComposable(props.playerId) you do not get the changes. You need to pass actually a ref / computed or the whole props object to keep the reactivity across your component and composable. So:
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
computed(() => props.playerId)
)
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
computed(() => props.playerId)
)
Would work, while
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
)
const { selectedPlayer, selectedThrows } = usePlayerData(
players,
props.playerId
)
will not.
sirlav0ie
sirlav0ie2mo ago
Legend. Thank you for the explanation! Why passing the whole props object does not work to my composables? UsePlayerData(props)
Mähh
Mähh2mo ago
<script setup lang="ts">
interface MyProps {
playerId: number
}

const props = defineProps<MyProps>()

const {itsReactive} = useTest(props)
</script>

<template>
<div>
player id props: {{ props.playerId }}<br/>
composable player id: {{itsReactive}}
</div>
</template>
<script setup lang="ts">
interface MyProps {
playerId: number
}

const props = defineProps<MyProps>()

const {itsReactive} = useTest(props)
</script>

<template>
<div>
player id props: {{ props.playerId }}<br/>
composable player id: {{itsReactive}}
</div>
</template>
export default (props) => {
const itsReactive = computed(() => props.playerId)

watch(() => props.playerId, (newVal, oldVal) => {
console.log('changed', newVal, oldVal)
})

return {
itsReactive
}
}
export default (props) => {
const itsReactive = computed(() => props.playerId)

watch(() => props.playerId, (newVal, oldVal) => {
console.log('changed', newVal, oldVal)
})

return {
itsReactive
}
}
Works for me.
sirlav0ie
sirlav0ie2mo ago
Uhm ok
Want results from more Discord servers?
Add your server