I got a v-if and if the Condition is true it should show some other vue elements
<template v-if="$store.state.Zell_Open[$store.state.PAGENUMBER]===true">
my state:
Zell_Open: [false],
PAGENUMBER: 0
When i change Zell_Open to true the component that should be shown is not shown, it will only be shown when i manually change the PAGENUMBER state (via Vue Dev tools) one up and one down, then the component that should be shown is shown.
I tried to use this as a work around and tryied to just change the PAGENUMBER state one up and one down when the Zell_open state is udated but this doesnt work too, it only works when using dev tools.
I also tried using v-show in a v-div instead of a v.if but that also just resulted in the same problem.
EDIT:
I tried using computed variables and i tried using getters instead of directly using the state but the i still got the same problem
To clarify:
It worked when i just used
<template v-if="$store.state.Zell_Open===true">
That was before the Zell_Open state was an array, there it worked.
So i think the [$store.state.PAGENUMBER] is causing the problem.
Try Vue.set in your store mutations:
https://v2.vuejs.org/v2/api/#Vue-set
And definitely move " $store.state.Zell_Open[$store.state.PAGENUMBER] === true " into a computed property. This way your template will remain clean of any logic.
You either have to make a getter in your Vuex store, then a computed property on the component and watch it like Vue data, or you can use a Vuex watcher to react on the changes. Vuex provides a watcher method Vuex watcher method like Vue's that you can use to watch for changes.
this.$store.watch(
(state)=>{
return this.$store.getters.your_getter
},
(val)=>{
//something changed do something
},
{
deep:true // when you have to watch arrays or objects
}
);
Related
I think this is more of a conceptual/architecture question but I will include code samples to help explain the question. I have a normalized redux state where the entities state slice looks like this:
entities: {
projects: {
[id]: {...},
[id]: {...},
...
},
assignments: {
[id]: {...},
[id]: {...},
...
}
}
And an individual assignment looks like this:
{
id: 1,
name: 'assignment 1',
status: 'active',
deadline: '01-01-2020'
}
I fetch this data from a backend DB. I am trying to figure out the proper way to handle the process of updating this data, keeping the UI responsive, and keeping my redux state in sync with the backend.
A specific example is a react component for displaying an individual assignment that has a picker/radio buttons to change the status between:
const statusOptions = {
'active',
'pending',
'complete'
}
The options I can see are:
1) Set the value of the picker as the props.assignment.status value, and in the onChange of the picker/selector dispatch an updateAssignment() action where a saga/thunk sends the POST request and immediately triggers a fetchAssignment() action which will send a GET request and update the redux state and in turn the component will re render.
The problem with this is the redux update takes too long so the UI appears laggy and the controlled input will revert to the old selection until the new props are passed in.
2) Set the local component state based on the redux state like this:
state = { status: this.props.assignment.status }
And then set the value of the picker based on the local state, which would provide near instant UI updates on a value change.
The problem I see here is I am pretty sure this is a react anti-pattern, and I would have to use getDerivedStateFromProps() or something similar to make sure the local state stays in sync with the redux state. Plus I really like the 'single source of truth' idea and I feel like this option would invalidate that.
3) set the value of the picker based on props.assignment.status and in the onChange handler of the picker clone the assignment object, update the status attribute, and then immediately send an updateAssignment() action that merges the locally created assignment object into the state.
After that send the POST request to the server and if it fails somehow revert the redux state to the prior state, basically removing the locally added assignment object. This seems kind of hacky though maybe?
Is there any agreed upon best practices for updating redux data while maintaining a single source of truth, snappy UI, and clean code?
The first part of (2) seems to me the right way.
In ComponentDidMount (or, even better, in App.js, when the app is starting) you fetch the data from the database to the redux state, and set the local state from it.
Then you maintain the data locally, and dispatch the proper action that will update the redux state and the database.
In shouldComponentUpdate you need to prevent updates that happen following this redux update: you will check if the values of the props have changed.
In componentDidUpdate you will update the state if the props change.
The last thing to take care of is getting data updates following database changes that happen by other instances of the app running on other smartphones, or by other sources of data, if this may happen. In firebase, for example, you do that by listening to relevant app changes. I don't know if this is relevant here.
okay, it's a little hard to explain, but i'll try.
i have some components rendered in a loop from an array of cards in my vuex store
<card-base
v-for="(card, i) in cards"
:class="`dashboard-card ${card.hidden ? 'hidden' : ''}`">
note the class depending on card.hidden, which is false onload
now, every <card-base> has a button (hide), which is supposed to.. well, hide it.
the way i try to do that is:
a v-btn in the card-base component gets a #clickproperty, which calls a method.
The Problem / Question
now i want to set the hidden property of the clicked card to true.
of course
minimizeDashboardCard() {
console.log(this.hidden)
this.hidden = true
}
doesn't work, because this is not the actual object from vuex, which provides the reactive properties, but just the "element".
if i set this.hidden = true, nothing changes (except the console.log correctly showing "true" after the first click)
but how can i access the actual vuex object from this? how do i get the index which i want to edit in my array? is there a way to have the card component "say" something like:
"dispatch an action that changes ME in the actual vuex array"?
like dispatch('hideCard', this) and have it actually working?
TLDR
how can i find out the index of the clicked card in the array, or directly target it in any other way? is there a connection between a rendered element and the array in store which defines it?
i hope you understood my problem :D
thanks!
I'm new to Redux so I'm sure this is something I'm missing, but I have a component that is subscribing to a Redux store, which is an observable of an array of objects. The problem is that even though a single property is changing on one of the objects, I'm returning a copy of the object, so Angular thinks everything changed and triggers a redraw. This would be fine except that my component has CSS transitions that don't get fired correctly because they should only react to the property change and now be removed and added again. Here's a simple example (pseudo code)
const state = {
items: [
{
open: false,
},
{
open: true,
}
]
}
Then a component is something like:
<div *ngFor='for let item of items'>
<div #openClose='item.open'>Some stuff</div>
</div>
So when my store sets the open property from true to false, instead of closing my component through a triggered animation, it simply redraws each div.
This must be a common problem, so is there an accepted way to set this up so the component is only created once?
{{str.split('').reverse().join()}}
{{arr.reverse().join()}}
This ERROR is shown while writing the second line.
You may have an infinite update loop in a component render function.
You must be in render a method, for e.g. rendering the list of item using some state value.
NOTE: render method is triggered whenever any state changes.
Also, since you are using Vue, take full advantage of Vue's computed property:
computed: {
yourComputedFunction: function() {
return arr.slice().reverse().join();
}
}
In your HTML: {{yourComputedFunction}}
I've got a React component with an input, and an optional "advanced input":
[ basic ]
Hide Advanced...
[ advanced ]
The advanced on the bottom goes away if you click "Hide Advanced", which changes to "Show Advanced". That's straightforward and working fine, there's a showAdvanced key in the state that controls the text and whether the advanced input is rendered.
External JS code, however, might change the value of advanced, in which case I want to show the [advanced] input if it's currently hidden and the value is different than the default. The user should be able to click "Hide Advanced" to close it again, however.
So, someone external calls cmp.setState({advanced: "20"}), and I want to then show advanced; The most straightforward thing to do would just be to update showAdvanced in my state. However, there doesn't seem to be a way to update some state in response to other state changes in React. I can think of a number of workarounds with slightly different behavior, but I really want to have this specific behavior.
Should I move showAdvanced to props, would that make sense? Can you change props in response to state changes? Thanks.
Okay first up, you mention that a third party outside of your component might call cmp.setState()? This is a huge react no-no. A component should only ever call it's own setState function - nothing outside should access it.
Also another thing to remember is that if you're trying change state again in response to a state change - that means you're doing something wrong.
When you build things in this way it makes your problem much harder than it needs to be. The reason being that if you accept that nothing external can set the state of your component - then basically the only option you have is to allow external things to update your component's props - and then react to them inside your component. This simplifies the problem.
So for example you should look at having whatever external things that used to be calling cmp.setState() instead call React.renderComponent on your component again, giving a new prop or prop value, such as showAdvanced set to true. Your component can then react to this in componentWillReceiveProps and set it's state accordingly. Here's an example bit of code:
var MyComponent = React.createClass({
getInitialState: function() {
return {
showAdvanced: this.props.showAdvanced || false
}
},
componentWillReceiveProps: function(nextProps) {
if (typeof nextProps.showAdvanced === 'boolean') {
this.setState({
showAdvanced: nextProps.showAdvanced
})
}
},
toggleAdvancedClickHandler: function(e) {
this.setState({
showAdvanced: !this.state.showAdvanced
})
},
render: function() {
return (
<div>
<div>Basic stuff</div>
<div>
<button onClick={this.toggleAdvancedClickHandler}>
{(this.state.showAdvanced ? 'Hide' : 'Show') + ' Advanced'}
</button>
</div>
<div style={{display: this.state.showAdvanced ? 'block' : 'none'}}>
Advanced Stuff
</div>
</div>
);
}
});
So the first time you call React.renderComponent(MyComponent({}), elem) the component will mount and the advanced div will be hidden. If you click on the button inside the component, it will toggle and show. If you need to force the component to show the advanced div from outside the component simply call render again like so: React.renderComponent(MyComponent({showAdvanced: true}), elem) and it will show it, regardless of internal state. Likewise if you wanted to hide it from outside, simply call it with showAdvanced: false.
Added bonus to the above code example is that calling setState inside of componentWillReceiveProps does not cause another render cycle, as it catches and changes the state BEFORE render is called. Have a look at the docs here for more info: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
Don't forget that calling renderComponent again on an already mounted component doesn't mount it again, it just tells react to update the component's props and react will then make the changes, run the lifecycle and render functions of the component and do it's dom diffing magic.
Revised answer in comment below.
My initial wrong answer:
The lifecycle function componentWillUpdate will be ran when new state or props are received. You can find documentation on it here: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate
If, when the external setState is called, you then set showAdvanced to true in componentWillUpdate, you should get the desired result.
EDIT: Another option would be to have the external call to setState include showAdvanced: true in its new state.