Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 10 months ago.
Improve this question
I have a computed property based on some nested object properties. When the object gets changed, the computed property seems to update (In vue-dev-tools) but the change is not reflected in the UI. I'm aware of nested object reactivity, but I never change/assign a nested property of my order object, the only time it changes is in the updateOrder() (which assigns the object at the root level.
Is there a reason why my UI isn't updating? Are the dev tools synced to the sames state as the UI is? Am I missing something about Vue's reactivity system?
Here is some very simplified code:
<template>
<my-component
#order-changed="updateOrder"
/>
<div v-if="isOrderComplete">
Your order is complete // this never shows until I refresh page
</div>
<div v-else>
Please Submit the order // this shows at first
</div>
</template>
export default {
props: function(){
initialOrder: Object,
},
data: function(){
order: this.initialOrder
},
methods: {
updateOrder: function(newOrder){ // gets triggered by a child component
this.order = newOrder;
}
},
computed: {
isOrderComplete: function(){ // starts as false, becomes true later, seems to be updated in dev-tools
return this.order.foo || this.order.bar
}
}
}
Nested objects does not automatically update computed properties, you can watch for changes in the Watch property.
watch: {
'order.foo'(newValue) {
// * If any changes happed, this will be triggered !
}
}
TLDR: Make sure you don't have any javascript errors in the console
I could not reproduce the error in an isolated codepen. So I figured something else was going on. I had some errors being thrown from a side effect of updating my order. They seemed unrelated, but once I fixed all my errors, the bug went away. I think the error short-circuited the Vue lifecycle even if the error had nothing to do with my computed property.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 17 days ago.
Improve this question
In functional programming, a pure function returns the same value for the same arguments.
I'd like to hear tips for writing in React sometime. I definitely do a lot of thinking at some point.
For example, the onClickHandler in the code below is not a pure function because it depends on an external state change.
const { useState } = require("react")
const Example = () => {
const [list, setList] = useState(["a", "b", "c", "d", "e"])
// Delete item from list, when button is clicked
// This function is non-puer because it uses external state (list, setList)
const onClickHandler = (e) => {
const newList = list.filter(item => item !== e.target.innerText)
setList(newList)
}
return (
<div>
{list.map((item, index) => {
return (
<div key={index}>
<button onClick={onClickHandler}>{item}</button>
</div>
)
}
)}
</div>
)
}
export default Example
In this case, is it good to write these codes as pure functions?
If not, should it be written as a pure function only at the component level?
I want to hear from programmers who are interested in React.
What side-effects are there when you have a component with a click handler?
You have the action of appending/updating HTML elements to the DOM
you have the action of firing an event when the user interacts with it
and you have the action of mutating state.
Which one of these side-effects do you actually manage yourself when you use something like Redux for example? None of them.
A component which does not close over mutable free variables and merely describes the creation of DOM nodes without controlling what should be done with them or with their events when they fire, is pure.
The way you use something like Redux in a functional way is that your click handler should only send a signal to Redux saying "I have been pressed, and here are some contextual infos like the cursor coordinates, etc.". It is another piece of code somewhere else which decides how this event will affect the state, and when you write that external piece of code you don't decide how and when it will be executed either, and you won't even mutate the state yourself.
It is React which appends and updates nodes in the DOM, it is the browser which fires events, it is Redux which updates the state. From the point of view of your pure functional component, there are only inputs parameters and an output which is a description of an action, but is not an action itself. It is a pure function.
When you write functional code you very often voluntarily loose control over the execution by letting a framework manage all the side-effects in a predictable way, so that your code remains pure and declarative.
The paradigm shift is that, instead of having every component handle its state independently and collaborate with other components, like cells in an organism, there is a coordinator which knows about the whole state of the world, receives orderly signals about what happens in the app and takes all the decision regarding the creation of a new, updated but snapshot isolated, state of the world. This new state is then passed to the render function and the cycle starts again, with state flowing in a single direction.
The updated React docs describe "purity" as "always return the same JSX given the same inputs." (I would also add that components' render functions shouldn't have externally visible side effects.)
This isn't quite the same as a purely mathematical or functional programming definition of purity: In your example, each time you call Example, the onClick handler that's passed to the DOM will be a different function instance, and the useState hook gives the possibility of state and mutation. However, it meets React's expectations:
A major purpose of hooks is to allow for side effects and state, so that's okay.
Even if the specific onClick function changes, the behavior ("this node responds to a click event and does XYZ") is the same.
If you did violate React's expectations (by having side effects or by rendering different JSX), then bugs are unlikely.
Beyond that, taking a functional programming style approach and using pure functions can make code more maintainable and can fit better with React's conventions and ecosystem. For example, in your Example:
setList is guaranteed not to change, so it's reasonable to not consider it as an external state dependency for onClickHandler.
onClickHandler can use an updater instead of directly depending on the list state. As explained in the React docs, this isn't required, but it can be helpful (especially once you get into effects, callbacks, and more complex state updates.)
const onClickHandler = (e) => {
setList(list => list.filter(item => item !== e.target.innerText))
}
i am having a problem trying to update some template properties if a Vuex store value changes
when i'm setting the value to undefined inside my store action (for example commit('SET_SELECTED_TICKET_ATTACHMENTS', undefined);), everything seems to work fine.
When setting the value to null however (commit('SET_SELECTED_TICKET_ATTACHMENTS', null);, my watch function will not fire.
The watch function in question looks like this:
selectedTicketAttachments () {
this.isTicketAttachmentLoading = false;
}
The mutation looks like this
SET_SELECTED_TICKET_ATTACHMENTS(state, selectedTicketAttachments){
state.selectedTicketAttachments = selectedTicketAttachments;
},
Any help would me much appreciated!
as EstusFlask has already mentioned, the commit will not be executed if the state will not be changed. My problem was that, under certain conditions, null will already have been commited at a time at which the execution of my watch handler would have gone unnoticed.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I want to change a value in the parent component by changing the state in the child component which is passed by props.
// This is the parent component
const [showEdit, setShowEdit] = useState(false);
<EditApplicationSettings
appSettings={appSettings}
changeState={(showEdit) => setShowEdit(showEdit)}
/>
// This is the child component
export default function EditApplicationSettings({ appSettings, props }) {
return (
<button
className="button-red"
onClick={() => props.changeState(false)}
>
Cancel
</button>
);
}
When I click on the button, that should change the state in parent, but instead, I get an error.
TypeError: Cannot read properties of undefined (reading 'changeState')
Where did I do wrong in passing the props?
In React terms props tends to refer to the entire property object:
EditApplicationSettings(props)
But since you're destructuring the properties from the object you need to reference the changeState property explicitly:
EditApplicationSettings({ appSettings, changeState })
and
onClick={() => changeState(false)}
To solve this error
TypeError: Cannot read properties of undefined (reading 'changeState')
then this line
export default function EditApplicationSettings({ appSettings, props }) {
should be
export default function EditApplicationSettings({ appSettings, ...props }) {
^^^
You could read more at MDN doc for destructuring assignment
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I have fetched the array using the graphql query and stored it in a variable called mpbrands. Now I want to store it in the state and render it in my component. I tried the below but its not giving any response
constructor(props) {
super(props)
this.state = {
count: 0
}
}
async componentDidMount(){
let brandQuery = BrandPageInstance.getBrandList();
await fetchQuery(brandQuery).then((mpbrand) => {
this.setState({
count: mpbrand.items
})
console.log(count)
},
(error) => console.log(error)
)
}
In the console I am getting an error Uncaught (in promise) ReferenceError: count is not defined . My array structure is
mpbrand:
items: Array(10)
0: {default_value: "CHEVROLET", image: "image_url"}
Let me know how to do it. Since I am newbie not able to store it in the state
Try console.log(this.state.count) That should solve the reference error.
count is part of the state object. So you can access it via this.state.count.
First of all count is not your state. It's the property state.
Secondly, replacing console.log(count) with console.log(this.state.count) won't work (in the essence that you won't see count updated) since your new state will only be available to you in next render.
But setState provides a second callback where you can access the updated state like so :-
this.setState({
count: mpbrand.items
},()=>console.log(this.state.count))
So I have a Vue page where I'm looping through a few items and I have the following code:
<div v-if="behavior !== 'selected' && filterItems.length >= 5"></div>
<div v-for="(itemName, index) in filterItems" :key="index">[stuff]</div>
Basically I'm looping through some items from an API, but I also want to conditionally show an element if there's 5 or more of those items, otherwise I want it hidden. That element needs to exist outside the loop, but it needs to check how many items are in the loop.
Interestingly enough, the above code works, but it also throws console errors, presumably because I'm accessing "filterItems" outside of the loop itself.
(here's the console error: [Vue warn]: Error in render: "TypeError: Cannot read property 'length' of undefined")
Any ideas on how I can avoid throwing these errors and accomplish what I need in as vue-native a way as possible?
As requested, here's the code declaring filterItems. It's just a prop declared as an array:
props: {
filterItems: Array,
behavior: String,
},
It's being passed in from a parent component as an array.
UPDATE: A POSSIBLE SOLUTION?
So I don't know if this is the best way to do this or not, but I was able to get the desired result by doing the following. I'd love to hear feedback on if this is a satisfactory solution:
I added a data value:
data() {
return {
displaySearch: false,
};
},
Then added:
updated() {
if (this.behavior !== 'selected' && this.filterItems.length >= 5) {
this.displaySearch = true;
}
},
Then ran a check against the new boolean: v-if="displaySearch"
My thinking is that the check run against displaySearch after the page renders and it avoids the TypeError. I tried mounting it, intially and it broke immediately.
Final Solution
See the answer below from Stephen Thomas. I settled on this as it appears to me to be the simplest and most elegant answer.
presumably because I'm accessing "filterItems" outside of the loop itself.
Nope. filterItems is not defined by the v-for loop. It's defined (or it should be defined) in the component's props object. As such, it's completely accessible anywhere in your template.
TypeError: Cannot read property 'length' of undefined"
That indicates that filterItems isn't defined. The parent that includes this component isn't providing a value. You can define a default (empty) array for the property:
props: {
filterItems: {
type: Array,
default() {
return [];
}
},
behavior: String
}
or you can fix the parent
I think it starts the filterItems as an empty array already solves, for example:
date () {
return {
filterItems: []
}
}
Vue doesn't allow declared properties to be accessed outside v-for (to avoid clashes between properties)
you can declare a global boolean variable to show or hide the component? or inject a property into your objects to hide or show