I'm struggling with useEffect that's not triggered at app load, but is on a click on a button. here my code:
export default function Person() {
const [person, setPerson] = useState({});
const [hitRandomUser, setHitRandomUser] = useState(0);
const fetchData = setCallback(async () => {
const api = "http://localhost/api/person/random";
const response = await fetch(api);
const data = await response.json();
setPerson(data);
console.log(data);
}, []);
useEffect(() => {
fetchData();
}, [hitRandomUser]);
const pax = {
id: 1549,
name: "Mikel",
sexe: "boy",
pop: 1
};
const onLike = () => {
setHitRandomUser(hitRandomUser 1);
console.log(hitRandomUser);
console.log("liked");
};
return (
{!person.id && <h1>Loading...</h1>}
<PersonCard person={person} onLike={onLike} />
);
}
so this code is actually crashing my app. the problem is that useEffect is never triggered with make person
an empty dict and then crashed at PersonCard
when it tried to fetch person.id
However if I pass pax
to PersonCard
, everything works just fine. When I use the onLike
function from PersonCard
, then hitRandomUser
state changes, and in that case useEffect
is correctly triggered as it's a dependency.
How can I make useEffect triggers at load, or setPerson
so I can use it to render?
update
The issue i see is that if I use pax
unstead of person
to render my component like this:
return (
<PersonCard person={pax} onLike={onLike} />
);
I can see that the useEffect
is actually rendered correctly because I can see the result of the console.log(data)
with is displayed and correct. So there should be something firing an error, but I can't see it.
CodePudding user response:
In this case useEffect
is not running most likely due to the error that is happening during initial render. The Component lifecycle can give you some idea of what runs when and where.
I suggest using an early return statement (in our discussion you used a standard conditional inside the JSX, which works as well, but I believe early return is a much better fit for this use case).
You can do something like placing this:
if (!persona.id) {
return <div>Loading…</div>;
}
// Other return goes here
Right above the return statement that renders PersonCard
. This will stop execution and instead display the loading message until the precondition is met, in which case React will automatically re-evaluate and re-render the component.
CodePudding user response:
ok, this actually fixed my issue:
{!person.id && <h1>Loading...</h1>}
{person.id && <PersonSwitchCard person={person} onLike={onLike} onDislike={onDisLike} />}
thanks a lot @CristianHG