How to watch for state/UI changes in vue.js - javascript

is there a way I can watch for a state change in the UI?
For example, in my data component I have a variable called loggedIn. If the value of loggedIn is equal to false, I want my header to display a Login link. Likewise, if the value of loggedIn is equal to true, I want my header to display a Logout link. So far I have tried:
<li v-if="loggedIn"><a v-link="{ path: 'login' }" v-on:click="logout()">Logout</a></li>
<li v-else><a v-link="{ path: 'login' }">Login</a></li>
data: function () {
return {
loggedIn: this.isLoggedIn() //this method returns true/false
}
},
The code as is has the desired effect. However, it only works if my component is refreshed. I would like Login/Logout to render accordingly when the value of loggedIn changes... Can someone help?
Thanks in advance!

Update I just realized that this.isLoggedIn is a method in your component, and not outside it. It looks like you should make isLoggedIn a computed and use that in your directives.
Yes, you can watch for a state change in the UI, but Vue cannot. Vue does not know that the UI as a whole exists. It only knows about the pieces you tell it about (usually via directives).
In your example code, you initialize loggedIn to the output of a function, but after being initialized, its value is never changed. There is no $watch for things that are outside the ViewModel.
Presumably, there is some login process in which the UI state changes. Since the purpose of the ViewModel is to model the application, you should implement that
login process as a method in your ViewModel. Among the things it will do is change the value of the loggedIn variable. As a general rule, UI state should be represented by data members, and anything that changes UI state should be implemented as a method.
It may be that logging in happens up the parent tree from this component. In that case, loggedIn should come in as a prop.

Related

Is there a function in ReactJS to wait for a Redux Action to be complete before loading anything in a class?

Is it possible to wait for a Redux action to be completed before loading anything in the class?
I have a page which uses data from logged-in users and the data is stored in a Redux state. In my React class, I'm calling the data in the Redux state to be used dynamically. If the user isn't logged in, the code will run into an error because the logged-in data is not present. How do I make it such that the code will wait for the Redux action to check if the user is logged-in, then if they are not logged in they will be redirected to another page before the data gets rendered and before the error occurs?
Anything like
on('REDUX_ACTION_LOGGED_IN', () => {})
will be useful.
I also saw an online package about something like redux-wait-for-action. Can someone teach me how to implement this here? The documentation isn't very clear.
I think you could look at this a different way.
You could check if the variable/data exists and if not then do something else.
Redux re-renders the component when the state changes. This means you do not have to wait for it to happen.
Something like this in your render probably would do:
render(){
<div>
{someDataAfter.login ? <div> I am logged in!</div> : <div> I am logged out</div>}
</div>
}
Just for completeness sake here is a link to explain the ? (ternary if) in the render function.
Another solution is to wrap the component with another one. This parent component can check if the user is loggedin. If it is then you can display the logged in component so:
render(){
{loggedIn && <MySecuredComponent/>
}
This will not render or load MySecuredComponent until loggedIn is true. Meaning componentDidMount will not fire in MySecuredComponent until loggedIn is true.

changing props in react_component when using react_rails

I am using this helper to display a datepicker component
<%= react_component "MyDatePicker", startDate: '', endDate: ''%>
I want to pass javascript values to startDate and endDate props. Any possible way to do this?
I don't really know what you're trying to do here exactly but if you just want to get values of your props from the component to your rails controller, do the following.
You can set state of your props in your react component and send an ajax request whenever the user selects a date.
Fixed this by using Pubsub. What I did is publish the user selected values in the javascript first. Then on react parent component lifecycle method subscribed to the previously published event and use setState to change the state based on that.
Now am on mobile but i will publish the code for clarity once i got access to a pc.
update
Using pubsub is easy. First we need to publish the required from anywhere using javascript
dates={some_value:value, another_value: value }
PubSub.publish(OFFLINE_BOOKING_DURATION, dates)
Here I just pass a dates object. You can pass anything.
Then in react's componentDidMount state I subscribe to this
componentDidMount: function () {
this.token = PubSub.subscribe(OFFLINE_BOOKING_DURATION, this.subscriber)
},
Here the first is object we are expecting and the callback
so here is the call back function here you can do anything like ajax call, set state, or anything
subscriber: function (msg, data) {
#this method gets called on receiving data
#we can access the data we passed like this
data.some_value},
And finally unsubscribe when component unmounts
componentWillUnmount: function () {
PubSub.unsubscribe(this.token)
}
This is how I implemented it. I no longer have the code but I hope you got the point.

React JS: How should I manage a data refresh when compement updates?

I am new to React, and I wanted to re-request data to a REST server after login in case of "session expired error".
When the component mounts, it fetches the data from the network. However, if session has expired, I receive an unauthorized error. This error is managed by a parent component, which shows the login form to reactivate session. I did that like this because I have many components that should behave like that (re-request after login).
<Parent>
<Component1/>
<Component2/>
...
</Parent>
If a "session expired error" is triggered Parent's state changes and it shows the login form. After login, Parent's state changes again and all visible components should update their data. The ComponentX method called when Parent's state is changed is ComponentWillUpdate and ComponentDidUpdate, so I placed the following code in ComponentWillUpdate:
if (!this.state.gotData && !this.updating){
this.updating = true;
this.setState({gotData:true},
()=>{this.updating=false; this.getData();});
}
which does the following: if it was not able to get the data from the network and it is not getting data at the moment (!this.updating flag), it requests the data through this.getData method. gotData is updated in optimistic assumption, and it is set to false if getData method fails.
I know that setState should not be used in componentWillUpdate method, but I have not found a better solution to this. Maybe I could add a validSession prop to all components, then set it to false when "Parent" gets the "expiration" error, and set it to true when login is done. And re-request data from in componentWillReceiveProps instead of componentWillUpdate.
Another possible solution would be to subscribe components to a global "re-login" event, and do the data request inside the listener.
How would you do that? Maybe my approach is completely wrong from the beginning...

One-Way Data Flow: Child component doesn't update when prop is asynchronously updated by parent

All props form a one-way-down binding between the child property and
the parent one: when the parent property updates, it will flow down to
the child, but not the other way around. This prevents child
components from accidentally mutating the parent’s state, which can
make your app’s data flow harder to reason about. In addition, every
time the parent component is updated, all props in the child component
will be refreshed with the latest value. - One-Way Data Flow
The Vue2 Component Docs suggests doing the following to use props as an initial value:
// via https://v2.vuejs.org/v2/guide/components.html#One-Way-Data-Flow
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
So in my code I mimicked those instructions here.
However data() in Note.vue isn't being updated even though the prop value is received according to vue-devtools.
Haven't had success setting the values with the mounted or created lifescyle methods.
When I use static data, this seems to work fine, how can I ensure the child component reacts to receiving props when it comes from a remote source?
When you are passing initialNote as prop for initial value, but I see initialNote is being populated asynchronously in getNote method, so it will not be present initially when the component will be mounted. It will be populated after some time by the time initialisation would have already happened.
In the example give in vue documentation, initialCounter is static value which will perfect as it will have same value from beginning.

Possible React Antipattern: Setting initial state from props

I've read up on this a bit but have not received a satisfactory answer. Granted I'm very new to React.
Suppose I have two components, Parent and Child. Parent passes a property to Child, and Child wishes to set a state to that property, as follows:
// in child
getInitialState: function() {
return ({
filters: this.props.filters
});
}
Then, this.state.filters gets modified through the UI, and upon clicking a "Save" button of some sort, saves the updated filters through a Flux-like model via a Store/Dispatcher up through to the Parent, which then re-renders and propagates down the updated this.props.filters down to Child again. This is kind of silly, as Child already has the updated data in its state, but whatever.
In order to check if the "Save" button should be active, I check in Child if:
this.state.filters === this.props.filters
If they are not equal, then the state has been changed from the original default prop. Thus, the "Save" button is activated. Otherwise, the state is identical to the original default prop, and the "Save" button is disabled.
My question is, is this flow an anti-pattern? Seems like it must be.
Within your component you want to know if a value has been modified from the last known value. This approach feels quite reasonable to me. Obviously there are other ways to do this, but I don't see anything wrong with this approach.
About this: "...saves the updated filters through a Flux-like model via a Store/Dispatcher up through to the Parent." Think of it more as stepping out of the rendering flow and into a state-updating flow in your app. The one-way nature of the flux pattern can be a bit more typing, but leads to more manageable code in the long run (e.g. if more than one component needs the updated state).
You are right that the Child already has the soon-to-be official state which will be received again from the Parent as props shortly. The Child can/should render based on that new state even though it's not been saved to the server yet - this is called Optimistic Updates https://facebook.github.io/react/docs/tutorial.html#optimization-optimistic-updates.
As long as the output of the render method doesn't change in the Child component after the new props are received from the Parent, React won't tell the browser to re-render the DOM. This means that your UI renders your desired state, but does so more quickly.

Categories