I am confused with the character of these two lifecycle methods. componentDidUpdate and componentWillReceiveProps. I am testing with two types :
existing task
new task
Check these two codes:
componentWillReceiveProps(nextProps) {
if (nextProps.jobId != this.props.jobId || (JSON.stringify(nextProps.locationData) != JSON.stringify(this.props.locationData))) {
console.log(nextProps.locationData.locations.locationDetails);
this.props.initLocationData(nextProps.locationData.locations.locationDetails);
}
}
componentDidUpdate(prevProps, prevState) {
if ((prevProps.jobId != this.props.jobId || (JSON.stringify(prevProps.locationData) != JSON.stringify(this.props.locationData)))) {
this.props.initLocationData(this.props.locationData.locations.locationDetails);
}
}
for the existing task, both methods are giving an exact correct result. For the new task, componentWillReceiveProps is giving last saved result but componentDidUpdate is giving proper result. If anyone can explain it correctly
Related
I wrote the code what get Json data and put in listPc. And wrote the loop that add value 'hostName' form listPc to pcBusy List. But my code only add values to second list, If I press GetButton values in pcBusy list duplicates. I need to update the pcBusy List, not only add the same values.
This print if I press button two times:
[S14, S18, S19, S12, S02, V08, S01, O09, S14, S18, S19, S12, S02, V08, S01, O09]
Thanks for help!)
void fetchDataStandart() async {
final urlAuth =
Uri.parse('http://XXX.XX.XXX.XXX/api/usersessions/activeinfo');
final response = await http
.get(urlAuth, headers: <String, String>{'authorization': basicAuth});
if (response.statusCode == 200) {
List listPc = List.from(json.decode(response.body)['result']);
for (int i = 0; i < listPc.length; i++) {
pcBusy.add(listPc[i]['hostName']);
}
print(pcBusy);
} else {
throw Exception('Ошибка получения данных');
}
}
TLDR: add Future<void> as your function return type and consider invoking pcBusy.clear() before overwriting with new data (depends on your logic, though).
With a little more context you'd help me giving you a more complete answer, but here's what I can see from your code:
Your button adds data as many times as you're pressing it. IF you press it two times, you'll get "double" the data, sooner or later. This happens because you use the add method, which just appends data on your list. You can either reset the values with pcBusy.clear() before you add values or do something else if you think that this function shouldn't be overwriting your list. This really depends on your logic;
You're awaiting a Future (via the async keyword), yet your Function doesn't return a Future. This means that - most likely - somewhere else you're awaiting for this function that in reality doesn't need to be awaited. As a consequence this means that when you first press the button, i.e. you fire the future, you can't await for it to happen and your UI doesn't update. The second time, it does update your UI with the previous result and the Future is fired again, letting it update your list with twice the values again as explained in step (1).
Hope this helps. EDIT. Here's some edited code:
// we want this function to be awaited: let it be a Future<void> async function
Future<void> fetchDataStandart() async {
// ... firing an async HTTP request
if (response.statusCode == 200) {
// if everything is OK, decode the JSON
List listPc = List.from(json.decode(response.body)['result']);
// the following will OVERWRITE the list.
pcBusy.clear(); // Or maybe save previous data somewhere else?
for (int i = 0; i < listPc.length; i++) {
pcBusy.add(listPc[i]['hostName']);
}
print(pcBusy);
} else {
throw Exception('Ошибка получения данных');
}
}
To remove duplicates you can convert the list to a set then back to a list again.
pcBusy.toSet().toList();
I have the following function
compareProducts = (empresa) => {
console.log(empresa.listaProductos)
let headerSetIn = false;
for (let i in empresa.listaProductos) {
//case1 : lookup for some data in an array, if found, setState and exit the whole function
if (pFichaInternacional && pFichaInternacional.length > 0) {
console.log("caso1")
let product: any = pFichaInternacional;
let nombreEmpresaApi = empresa.listaProductos[i].nombre
let productoFiltrado = product.filter(i => i.referencia == nombreEmpresaApi)
productoFiltrado = productoFiltrado[0]
if (productoFiltrado) {
headerSetIn = true
this.setState({
headerCardText: productoFiltrado.descripcion.toString(),
headerButtonText: productoFiltrado.label.toString(),
})
break;
}
}
}
//case 2: case1 didnt found the data, so we setup some predefined data.
if (!headerSetIn && pFichaInternacional.length > 0) {
let product: any = pFichaInternacional;
this.setState({
headerCardText: product[0].descripcion.toString(),
headerButtonText: product[0].label.toString()
})
}
}
Im receiving a
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
I have also tried using a setstate , instead of a local variable to set the headerSetIn parameter. But if I do it, I think js doesnt have time to evaluate the change, and both are executed, instead of only 1
Ive tried to use () , => after the first state, but it doesnt make sense in my flow
As far as I can understand is that you are calling setState in a for loop, which is not a good thing. Every time a certain condition is met setState is called, so you are constantly setting the state and rerendering smashing your performance and causing this.
I would suggest using a variable and get the needed data in the for loop then after you have excited the for loop simply use setState to set the state after all the data has been looped trough.
I am trying to filter a List with multiple conditions. The main thing is, I must use the condition if it is true and not if it is false. If the condition is false I should not use that to filter. Below is my code
void performFiltering(bool homeVisits, bool onTheSpotServices)
{
//Check for home and on the spot filtering
if(homeVisits==true)
{
filteredOrganizationList = orgList.where((org) => org.homeVisits==true);
}
else if(onTheSpotServices==true)
{
filteredOrganizationList = orgList.where((org) => org.onTheSpotService==true);
}
else if(homeVisits==true && onTheSpotServices==true)
{
filteredOrganizationList = orgList.where((org) => (org.onTheSpotService==true) ||(org.homeVisits==true) );
}
}
here I have made simple if-else statements. Nothing serious. But I can't do this when there are more conditions. Luckily it is just 2 conditions, but I have much more to come.
Also carefully notice that I have used OR Command in the last statement. That means get results where either homeVisits=true or onTheSpotServices=true
Whats the most effective way of handing this?
there is no need for a cascade of multiple if-elses
instead use a single where with a custom test function:
filteredOrganizationList = orgList.where((org) =>
homeVisits && org.homeVisits ||
onTheSpotServices && org.onTheSpotService ||
... // rest of your filter tests
);
Note for the readers: this question is specific for Codename One only.
I'm developing an app that needs some initial data from a server to run properly. The first shown Form doesn't need this data and there is also a splash screen on the first run, so if the Internet connection is good there is enought time to retrive the data... but the Internet connection can be slow or absent.
I have in the init a call to this method:
private void getStartData() {
Runnable getBootData = () -> {
if (serverAPI.getSomething() && serverAPI.getXXX() && ...) {
isAllDataFetched = true;
} else {
Log.p("Connection ERROR in fetching initial data");
}
};
EasyThread appInfo = EasyThread.start("APPINFO");
appInfo.run(getBootData);
}
Each serverAPI method in this example is a synchronous method that return true if success, false otherwise. My question is how to change this EasyThread to repeat again all the calls to (serverAPI.getSomething() && serverAPI.getXXX() && ...) after one second if the result is false, and again after another second and so on, until the result is true.
I don't want to shown an error or an alert to the user: I'll show an alert only if the static boolean isAllDataFetched is false when the requested data is strictly necessary.
I tried to read carefully the documentation of EasyThread and of Runnable, but I didn't understand how to handle this use case.
Since this is a thread you could easily use Thread.sleep(1000) or more simply Util.sleep(1000) which just swallows the InterruptedException. So something like this would work:
while(!isAllDataFetched) {
if (serverAPI.getSomething() && serverAPI.getXXX() && ...) {
isAllDataFetched = true;
} else {
Log.p("Connection ERROR in fetching initial data");
Util.sleep(1000);
}
}
Is the following react code wrong ?
state={ foo: { bar: true } } // line 1
setState(state) // line 2
state.foo.bar = false // line 3
setState(state) // line 4
If yes, why ?
This suggest that it is wrong, but does not explain why ?
I think it is not wrong, for the following reason:
at line 2 vdom1 is created
at line 4 vdom2 is created
vdom1 and vdom2 are compared
difference is propagated to the actual DOM
If this is the case, then mutating state at line3 should not have any effect on what happens at line4.
In other words:
this should be equivalent code:
state={ foo: { bar: true } } // line 1
setState(state) // line 2
state={ foo: { bar: false } } // line 3
setState(state) // line 4
Is this code equivalent to the one above ?
If not, why not ?
Creating an immutable clone of state is a good idea because of the way state changes are compared in order to optimise rendering.
In lifecycle methods like shouldComponentUpdate, nextProps are passed in and can be compared to this.props.
If you mutate the state directly, then nextProps.prop1 and this.props.prop1 will always be the same and therefore you might not get the expected behaviour.
I'm sure there are other reasons as well, but this one seems like the most straight-forward.