I have two effects set up to instantiate some values in my stateless react component. However, I can't seem to access the data set by my first function in my second function.
From my reading it seems that these may be running asynchronously, so it isn't guaranteed when each of the functions will run. How do I get effects with common concerns to run synchronously when they depend on each others effects? Alternatively, is there actually a better practice for replacing a constructor
in a stateless react component?
Relevant code:
const [roadTiles, setRoadTiles] = useState([]);
...
useEffect(() => {
populateRoadTiles(); // calls setRoadTiles() -- console.log shows roadTiles has been set
populateRoadTileDivs(); // uses roadTiles -- roadTiles is still [] and causes index error
}, [])
I searched around for similar questions, but most of the solutions came down to individual bugs in the user's code. Hopefully this better distills the question.
EDIT:
Chaining dependencies seems to be the way to go based on Daniil's comment and the documentation.
However, I'm still running into the same problem. Maybe it's an issue with my logic in populateRoadTiles instead (below). The documentation seems to indicate that set*() functions are also async, so it could make sense that roadTiles is still unset after populateRoadTiles
.
BUT, with the new dependency structure, populateRoadTileDivs
is eventually called. This seems to indicate that roadTiles should have been set and triggered the second effect.
const populateRoadTiles = () => {
const newRoadTiles = new Array(height);
for (let r = 0; r < height; r++) {
newRoadTiles[r] = new Array(width);
}
for (let r = 0; r < height; r++) {
for (let c = 0; c < width; c++) {
newRoadTiles[r][c] = (
<RoadTile
onClick={() => getNeighbors(r, c)}
type={RoadTileType.EMPTY}
/>
);
}
}
setRoadTiles(newRoadTiles);
console.log(newRoadTiles); // populated array
console.log(roadTiles); // []
};
Each useEffect
has [dependency
] or has not []
=== componentDidMount
.
React run the effect after its the dependency changed.
const [roadTiles, setRoadTiles] = useState([]);
const [roadTilesDivs, setRoadTilesDivs] = useState([]);
...
useEffect(() => {
populateRoadTiles(); // calls setRoadTiles() -- console.log shows roadTiles has been set
}, [])
useEffect(() => {
populateRoadTileDivs(); // uses roadTiles -- roadTiles is still [] and causes index error
}, [roadTiles]) // <- add dependency here
if you want to log state keep it variable
setRoadTiles(newRoadTiles);
console.log(newRoadTiles); // not actual, but it will be correct
console.log(roadTiles); // [] actual but it's prematurely.