I tried to implement a simple data fetching example in ReScript-React, following the article How to fetch data with React Hooks, which I translated into ReScript as:
Whatâs the JS output? Maybe the useEffect function is not named the way that the eslint plugin recognises. If so, you could try adding the name to the list. Oh, wait, I got that wrong. Maybe the plugin doesnât recognise the name (or the module) of the useState hook, so it doesnât know that the setter is stable. Thereâs no list to add that to.
But of course, I wish some tool could do it for the ReScript code. Thereâs a reanalyze issue for that, by the by.
var match = React.useState(function () {
return [];
});
var setItems = match[1];
var items = match[0];
React.useEffect((function () {
var __x = fetchData(undefined, undefined);
__x.then(function (results) {
if (results.TAG === /* Ok */0) {
var data = results._0;
Curry._1(setItems, (function (param) {
return data;
}));
return Promise.resolve(undefined);
}
console.log("Fetching data failed with error: " + results._0);
return Promise.resolve(undefined);
});
}), []);
Could the warning be because of the way the tuple destructor was translated? If my code is indeed correct, perhaps the way to fix this is to translate the line as follows?
Could the warning be because of the way the tuple destructor was translated? If my code is indeed correct, perhaps the way to fix this is to translate the line as follows?
That could indeed be the case, I am not sure how the lint warning works.
I think most ReScripters disable those checks on generated files anyway. Or they use something else than CRA, like Vite which does not force eslint on you.
Itâs because the lint rule doesnât work unless you destructure the tuple returned from useState, and you canât force the rescript compiler to output JS that does that.
Our solution where I work is to always put setState functions in the dependency array anyway. Does no harm, and means you donât have to remember which things to put in the array and which not to.
By the way: in a large project, with enough people working on it, it is practically impossible to get all your dependency arrays correct without help from the linter. I think of myself as a very careful coder, and I still surprise myself by missing out dependencies quite often, which is only caught by eslint.
Writing React code without this lint rule is risky, and the kinds of bugs you can end up with if you miss out dependencies are the worst â those ones that are only discovered by users, when they do something weird like go back and forth between 2 views multiple times or click something too quickly.
Iâd love to have some other way to check this, but right now all we have is running eslint against the generated JS, and thatâs a lot better than trying to get the arrays right without any help from a computer.
Sounds like you use useEffect in a wrong way, because dependency array should be needed only for optimisations. I recommend the talk https://youtu.be/Ck-e3hd3pKw?t=4002 to get an idea how it intended to be.
My understanding was that itâs needed to tell React to run the effect specifically when a variable value changes. Not really an optimization. More an essential input to the system. Getting it wrong will lead to UI bugs (sounds like itâs happened to everybody).
My point is that itâs an error prone usage not intended by react team (see strict mode). If you canât remove all dependency arrays without breaking your application, then something is wrong.
I like this, but then itâs not easy to see from the code that this effect is meant to run only once on mount because you have to use useEffect1 instead of useEffect0:
This is actually a bit misleading, especially in Reactâs new concurrent mode. There isnât really such a thing as âon mountâ, because components can be mounted multiple times and aborted, then mounted again. Effects are bits of imperative logic that run based on inputs; if youâre thinking about them in terms of component lifecycles, then itâs probably a good thing that your code is forcing you to think about them a bit differently.
Aha, interesting, I didnât know about Reactâs new concurrent mode. So what would be the way to fetch remote data in an app only once at the begininng?