How to force a fetch in Relay modern - relayjs

My top-level component includes a settings dialog that includes the user's credentials. When a change is made in that dialog and the dialog is dismissed (state is changed to dialogOpen=false), I want to force a new fetch from the server since the credentials may have changed. In Relay classic, the top-level component includes a Relay.RootContainer and so I just passed forceFetch=true to that RootContainer. In Relay modern, my top-level component includes a QueryRenderer. So how do I force the refetch in this case?
I found this issue, https://github.com/facebook/relay/issues/1684, which seems to indicate that the QueryRenderer always refetches, but this doesn't seem to be the case in my testing. At least, I'm not seeing my fetchQuery get called after the state change/refresh when the settings dialog is closed. I think I'm probably not completely understanding the statements in that issue.
Can anyone clarify?

OK, I think I figured out my disconnect here. In checking the source for QueryRenderer (don't know why I didn't do this in the first place), I saw that a fetch will occur if props.variables changes. So I just defined a boolean instance variable called refetch and flip its value when my dialog is dismissed:
<QueryRenderer
environment={environment}
query={query}
variables={{refetch: this.refetch}}
Since this doesn't seem to well documented, I'll mention here that QueryRenderer will re-fetch when any of the following conditions is true:
current query parameter is not equal to the previous query parameter.
current environment parameter is not equal to the previous environment parameter.
current variables parameter is not equal to the previous variables parameter.

You can use the retry function that's passed to QueryRenderer's render.
<QueryRenderer
environment={environment}
query={graphql`
query MyQuery($exampleUserId: String!) {
user(userId: $exampleUserId) {
favoriteIceCream
}
}
`}
render={({ error, props, retry }) => {
// Here, you could call `retry()` to refetch data
// or pass it as a prop to a child component.
return (
<IceCreamSelectionView refetchData={retry} user={props.user} />
)
}} />

Related

React-Final-Form: Set initialValues from props, form state resets on props change

I have a component, that takes a balance prop, and this balance prop can change over time.
I then have a React Final Form to send a transaction, with usual fields amount to send, receiver... And in my validate, I just check that the user has enough balance to send the transaction.
However, if my balance changes when the user is inputting something, then the whole form resets. How would you only reset part of the form state?
See this codesandbox for an example: https://codesandbox.io/s/jn69xql7y3:
input something
wait 5s
see that the form state is blank again
I just ran into this issue with react-final-form where the form completely resets when any state change happens in a wrapping component.
The problem is here (from your codesandbox)
<Form
initialValues={{ amount: 0, balance }} <-- creates a new object on every render
The problem is that when initialValues changes the entire form reinitialises. By default, whatever you pass to initialValues is compared against the previous one using shallow equals, i.e. comparing reference.
This means that if you create a new object in the render, even if it's the same, the entire form resets when some state changes, the render function re-runs, and a new object with a new reference is created for initialValues.
To solve the general problem, if you just want to turn off the form resetting, what I've done is just move my initialState, which never changes, out to a variable so that it's the same reference on every render and therefore always appears to be the same to final-form with the default behaviour. I would prefer a configuration to actually completely turn off this reinitialisation behaviour, but I can't find one in the docs.
However if you actually want this, but need to modify it, the comparison behaviour can be configured using the initialValuesEqual prop (docs here), to do a deep comparison on the initialValues object for example.
You can also use the keepDirtyOnReinitialize prop to only reset the parts of your form that haven't been touched.
I would guess some combination of the above might solve your usecase, depending on the exact UX you need.
Adding onto what #davnicwil mentioned, my solution is useMemo() hook in func components:
const initialValues = useMemo(() => ({ amount: 0, balance }), [])
By using useMemo it creates only 1 object during the life of the component and subsequent re-renders don't cause initialValues to overwrite the form values.
Another solution is to use react-final-form Form prop initialValuesEqual={() => true}
<Form initialValues={{ amount: 0, balance }} initialValuesEqual={() => true} .../>
ref: https://github.com/final-form/react-final-form/issues/246

react-final-form how to load initialValues from ajax call

Looking at the example in https://codesandbox.io/s/km2n35kq3v
The initial values are hard-coded.
<Wizard
initialValues={{ employed: true, stooge: 'larry' }}
However, i want to make an ajax call in ComponentDidMount, fetch the initial values, then (re) set the initialValues when the call completes.
<Wizard
initialValues={this.state.myInitValues}
Nothing happens, when the form re-renders, the initialValues do not change - What am i missing ?
that example only works for hard-coded values
No.
As long as the values are fetched higher in the tree, "above" the <Wizard/> component, they can be passed in as props just fine. React Final Form even has fine grained isEqual() control over determining when the initialValues prop changes (in which case the form would be re-initialized) or not.
Hope this helps...
I figured this out.. that example only works for hard-coded values, I should not have assume otherwise.
It turns out initialValues are being passed down to the Wizard component and set as state within the Wizard component in the constructor.
When the ajax call returns, the constructor does not get executed again.

SWFAddress used to change INDIVIDUAL params in the url

I am using SWFAddress in actionscript 3 to control urls for navigation and controls, and while I am able to target and change specific parameters, I feel like I am missing a cleaner and more consistent way of handling it, perhaps even a feature or method I am not aware of.
Say I have a url and I want to change just the second param of def to xyz.
http://localhost/some-page/#/?param1=abc&param2=def&param3=ghi changed to
http://localhost/some-page/#/?param1=abc&param2=xyz&param3=ghi
I currently am doing:
if (SWFAddress.getParameterNames().indexOf("param2") >= 0) {
SWFAddress.setValue(SWFAddress.getPath() + "?"
+ SWFAddress.getQueryString().replace("param2=" + SWFAddress.getParameter("param2"), "param2=xyz"))
Essentially, checking if the param exists, checking what its current value is, then recreating the whole url using base, '?", and query, making sure I replace the the parameter and the parameter's value, making sure I don't miss the equal sign. This get's sloppy, and is error prone if the param exists but is not set to anything, or whether or not there is an equal sign, and a host of other pitfalls.
So, I can not just tell SWFAddress to update that one parameter in the url? A theoretical function of SWFAddress.setParam("param2, "xyz").
Has anyone coded their own method to micro-manipulate SWFAddress and the url, beyond the single function they supply you with of setValue(val:String)?
I think the short answer is no. According to the documentation there is no setParameter to go with the getParameter method. Looking at the code, it seems that the URL is not cached as a property in the class and therefore cannot be manipulated other than via the setValue method which, of course, updates the URL in the browser.
Presumably you're already parsing the URL in your onChange event so you can use the values to set your application state? If so, you shouldn't need to do so again when you come to rebuild the URL prior to updating it from Flash. If you store the deep-link properties on a Model class somewhere you can handle the defaulting, updating, and error checking without needing to resort to String manipulation. You would then rebuild the URL using those properties, a process you could abstract into a method in your Model class if required.
You should also note that the following line is not particularly robust since it will return true for properties such as param22 and sparam2:
if (SWFAddress.getParameterNames().indexOf("param2") >= 0) { }

Not able to set WorkItem State using TFS API?

I am trying to set State property value of Test Case Work item. I am creating using TFS API and C# code.
It throws an error while I save the test case using Save() method. I have called the Validate() method of a work item and the ArrayList shows the value I am trying to assign is an invalid state.
testCase.State = TestPointState.Ready.ToString();
ArrayList result = testCase.WorkItem.Validate();
if (!testCase.WorkItem.IsValid())
{
//this block executes
}
When I manually opened the MTM to see what are the different STATE values for existing work items, then I found READY and DESIGN. That's why I tried t assign TestPointState.Ready enum. I tried assiging READY string directly in that statement, but still the same exception whlie saving the test case.
Any idea on how to fix this issue ?
It is possible that when setting the state another field has then an invalid input. e.g.: when you change from Ready to Design it might require that you select who the AssignTo person is and so you'll need to populate these fields as well. You can use the Validate method to get a list of invalid fields after you set the state like below.
ArrayList invalidFields = newWI.Validate();

Emberjs - Temporary disable property changes notification

Is there any simple way to achieve a temporary disabling of notifications of an object property or properties?
I know you can defer them with beginPropertyChanges() and endPropertyChanges() but I don't want those changes to be notified at all until I explicitly enable them.
Thank you in advance.
Use case:
I have to set a property of an object (A) with another object (B). Properties of B are being observed by several methods of other objects. At some time the B object's data gets cleared and the observers get notified, later an HTTP response sets them with something useful. I would not want the observers get notified when clearing the object because the properties values are not valid at that moment.
Ember doesn't support suspending notifications. I would strongly suggest against toying with the private APIs mentioned in the above comments.
I wonder why you bother clearing the object's data prior to the HTTP request? Seems strange.
Using a flag will cause the computed to still trigger.
The best I've come up with is to override the computed with the last known value. Later you can enable it by setting the computed property definition again.
let _myComputedProperty = Ember.computed('foobar', function() {
let foobar = this.get('foobar');
console.log('myComputedProperty triggered >', foobar);
return '_' + foobar + '_';
});
Controller.extend({
turnOffComputed: function() {
let myComputedProperty = this.get('myComputedProperty');
this.set('myComputedProperty', myComputedProperty);
},
turnOnComputed: function() {
this.set('myComputedProperty', _myComputedProperty);
}
})
Full example: Conditional binding for a computed property
This is an old question, but it appears high in Google search for suspending observers, so I would comment.
There are evident use cases for such a feature, for example, an enum property of an object is represented by a list box and the object may change. If the list box is used to request property changes from the server and to set the new value on success, the natural way to do things is to use a controller property with the list box, set that property to the object property when the object changes, and observe it to make requests to the server. In this case whenever the object changes the observer will receive an unwanted notification.
However, I agree that these use cases are so diverse that there is no way Ember can support them.
Thus, a possible work around is to declare a variable in the controller and use it whenever you change a property so that you react only to changes made by the User:
doNotReact: false,
updateManually: function() {
this.doNotReact = true;
Ember.run.scheduleOnce('actions', this, function() {
this.doNotReact = false;
});
............
this.set('something', somevalue);
............
},
onChange: function() {
if (this.doNotReact) return;
...............
}.observes('something')
The value of doNotReact will be reset after the observer gets a chance to run. I do not recommend to reset the stopper variable in the observer since it will not run if you set the property to the same value it already has.

Resources