Is there any strategy for having you code run only once(like initState()) and have the context also available (to use .of(context)). For example I am getting Bloc.of(context) and I want to subscribe to it (do some stuff like showing an alert dialog, etc). Subscribing in build(), means subscribing multiple times
I can use didChangeDependencies() and set the subscription ??= bloc.listen, but I was wondering if there is another good strategy.
there is another way to do that , by add a "bool" variable and set it as "false" in the "initState" , and lets named (isExec)
2 - in the build method check if "isExec" == false , then run your code that you want to excute it once (alert , subscribe .. etc)
3 - change "isExec" to true (isExec = true);
now if your app state change the build method well avoid that code in the if statment
Related
I just started learning Flutter, and I'm going through the Udemy course "Flutter & Dart - The Complete Guide". In that course, there is a section about building a shopping app, which uses providers. In one instance of that app, where the user swipes to delete a product from the Cart page (or screen/route) with the help of the Dismissible widget, he uses a function inside the provider class, which takes a product ID, to delete the item from the cart.
Here is the thing that I don't understand. The Dismissible widget is connected to the provider via this code in the onDismissed property (which fires after the swipe):
Provider.of<Cart>(context, listen: false).removeItem(productId);
And it all works just fine like this. But if you remove the listen parameter (hence turning it into it's default state which is true), then the Dismiss animation still takes place, but the removeItem() method doesn't work, and the cart still stays the same.
Why does this happen?
When we use listen: false we are telling to not rebuild the widget after we remove an item, but they know that we are removing an item so we don't need to listen any value here it's just doing the action of removing
I'll refer to the method Provider.of(context, listen: true) as x throughout this answer.
x is expected to be used ONLY for properties of a Widget that is
expected to change; and
can be rebuilt. For example:
SizedBox(
width: Provider.of<MyLogic>(context, listen: true).width,
)
When used this way, x will ONLY be called when the context owner is being built/rebuilt.
To ensure that it is being used properly, x performs a sanity check every time it is called, making sure that the owner of the context you passed is actually being built/rebuilt. When you call x from within your onPressed or whatever method it is you call it from, x sees that the context owner is not in the "build" phase, and throws this error.
There are a few more details to this, but you don't actually need to know more about it (especially you're just beginning) unless you want to contribute to the package, in which case you should read their documentation.
Side note: you can now use context.watch() and context.read() instead of Provider.of().
When initializing a component using reactfire, each time I add a reactfire hook (e.g. useFirestoreDocData), it triggers a re-render and therefore repeats all previous initialization. For example:
const MyComponent = props => {
console.log(1);
const firestore = useFirestore();
console.log(2);
const ref = firestore.doc('count/counter');
console.log(3);
const { value } = useFirestoreDocDataOnce(ref);
console.log(4);
...
return <span>{value}</span>;
};
will output:
1
1
2
3
1
2
3
4
This seems wasteful, is there a way to avoid this?
This is particularly problematic when I need the result of one reactfire hook to create another (e.g. retrieve data from one document to determine which other document to read) and it duplicates the server calls.
See React's documentation of Suspense.
Particulary that part: Approach 3: Render-as-You-Fetch (using Suspense)
Reactfire uses this mechanics. It is not supposed to fetch more than one time for each call even if the line is executed more than once. The mechanics behind "understand" that the fetch is already done and will start the next one.
In your case, react try to render your component, see it needs to fetch, stop rendering and show suspense's fallback while fetching. When fetch is done it retry to render your component and as the fetch is completed it will render completely.
You can confirm in your network tab that each calls is done only once.
I hope I'm clear, please don't hesitate to ask for more details if i'm not.
I am using ag-grid/ag-grid-angular to provide an editable grid of data backed by a database. When a user edits a cell I want to be able to post the update to the backend service and if the request is successful update the grid and if not undo the user's changes and show an error.
I have approached this problem from a couple different angles but have yet to find the solution that meets all my requirements and am also curious about what the best practice would be to implement this kind of functionality.
My first thought was to leverage the cellValueChanged event. With this approach I can see the old and new values and then make a call to my service to update the database. If the request is successful then everything is great and works as expected. However, if the request fails for some reason then I need to be able to undo the user's changes. Since I have access to the old value I can easily do something like event.node.setDataValue(event.column, event.oldValue) to revert the user's changes. However, since I am updating the grid again this actually triggers the cellValueChanged event a second time. I have no way of knowing that this is the result of undoing the user's changes so I unnecessarily make a call to my service again to update the data even though the original request was never successful in updating the data.
I have also tried using a custom cell editor to get in between when the user is finished editing a cell and when the grid is actually updated. However, it appears that there is no way to integrate an async method in any of these classes to be able to wait for a response from the server to decide whether or not to actually apply the user's changes. E.g.
isCancelBeforeStart(): boolean {
this.service.updateData(event.data).subscribe(() => {
return false;
}, error => {
return true;
});
}
does not work because this method is synchronous and I need to be able to wait for a response from my service before deciding whether to cancel the edit or not.
Is there something I am missing or not taking in to account? Or another way to approach this problem to get my intended functionality? I realize this could be handled much easier with dedicated edit/save buttons but I am ideally looking for an interactive grid that is saving the changes to the backend as the user is making changes and providing feedback in cases where something went wrong.
Any help/feedback is greatly appreciated!
I understand what you are trying to do, and I think that the best approach is going to be to use a "valueSetter" function on each of your editable columns.
With a valueSetter, the grid's value will not be directly updated - you will have to update your bound data to have it reflected in the grid.
When the valueSetter is called by the grid at the end of the edit, you'll probably want to record the original value somehow, update your bound data (so that the grid will reflect the change), and then kick off the back-end save, and return immediately from the valueSetter function.
(It's important to return immediately from the valueSetter function to keep the grid responsive. Since the valueSetter call from the grid is synchronous, if you try to wait for the server response, you're going to lock up the grid while you're waiting.)
Then, if the back-end update succeeds, there's nothing to do, and if it fails, you can update your bound data to reflect the original value.
With this method, you won't have the problem of listening for the cellValueChanged event.
The one issue that you might have to deal with is what to do if the user changes the cell value, and then changes it again before the first back-end save returns.
onCellValueChanged: (event) => {
if (event.oldValue === event.newValue) {
return;
}
try {
// apiUpdate(event.data)
}
catch {
event.node.data[event.colDef.Field] = event.oldValue;
event.node.setDataValue(event.column, event.oldValue);
}
}
By changing the value back on node.data first, when setDataValue() triggers the change event again, oldValue and newValue are actually the same now and the function returns, avoiding the rather slow infinite loop.
I think it's because you change the data behind the scenes directly without agGrid noticing with node.data = , then make a change that agGrid recognises and rerenders the cell by calling setDataValue. Thereby tricking agGrid into behaving.
I would suggest a slightly better approach than StangerString, but to credit him the idea came from his approach. Rather than using a test of the oldValue/newValue and allowing the event to be called twice, you can go around the change detection by doing the following.
event.node.data[event.colDef.field] = event.oldValue;
event.api.refreshCells({ rowNodes: [event.node], columns: [event.column.colId] });
What that does is sets the data directly in the data store used by aggrid, then you tell it to refresh that grid. That will prevent the onCellValueChanged event from having to be called again.
(if you arent using colIds you can use the field or pass the whole column, I think any of them work)
Using Firebase, after I fetch and activate my remote config values, calling configValue(forKey key: String?) will give me the value from the remote source. I know I can call func configValue(forKey key: String?, source: RemoteConfigSource) or defaultValue(forKey key: String?) to get the default value. But, how do I reset my activated data so that calling configValue will give me the default values again?
Further, do the activated values persisted ever get purged?
Firebaser here with some additional info that could be helpful.
The Android SDK does have a reset method as of the v2 release that can do what you're looking for here. The reset() call will reset Remote Config to the state when it was first installed, and then you can call setDefaults() to reset to the default values and continue using them. From that point if you want to keep using these default values, you would want to avoid calling activate and fetch. Once you make those calls, the default values may get updated at the initial fetch call or following fetch intervals.
Also, the reset() isn't available in the iOS v2 SDK today, but it sounds like a reasonable request. Could you please file a feature request if this feature would be helpful for you?
What I'm up to is to get the jenkins job details and store it in mongo DB every "X" minutes. I have to make an HTTP.call(JenkinsURL) which I know how to do. My problem is calling it for specific intervals.
buildDetails=HTTP.call('GET',buildURL);
buildURL has the Jenkins job URL. I found this link which gives an overview of the code for my problem, but I don't know how and where i should place these code to get it working. I tried all possibility.
Is there any method in meteor which can make this possible to run a specific code to be run for every X min??
Is there any method in meteor which can make this possible to run a specific code to be run for every X min??
Yes, there is.
Meteor.setInterval that can be used to do something repetitively every X interval of time.
You can put your HTTP call within it on the server. Eg:
Meteor.startup({function(){
var timerID = Meteor.setInterval(function(){
buildDetails=HTTP.call('GET',buildURL);
// and other things
}, 60000) //60000ms = 1 min
}
});
When you want to stop the timer function, simply call Meteor.clearInterval
Meteor.clearInterval(timerID);