General Tips
Don't over-reach for effects
When building reactive components it's very common to use a useEffect
to "listen" to changes in values and respond to them, often updating state in the process. This isn't optimal though, and the React docs haven't done a great job explaining this.
const Component = () => {
const [pressed, setPressed] = useState(false);
const [colour, setColour] = useState("green");
useEffect(() => {
if (pressed) {
setColour("pink");
} else {
setColour("red");
}
}, [pressed]);
return (
<Box borderColor={colour}>
<Button onPress={() => setPressed(!pressed)} />
</Box>
);
};
In this example the component renders a button that updated a state value. In our effect we are "listening" for changes in that state value and updating the colour value accordingly. This entire effects process could be avoided entirely by extending the event handler passed to onPress
.
Note: This example is untested and not great, should be updated.
const Component = () => {
const [pressed, setPressed] = useState(false);
const [colour, setColour] = useState("green");
const handlePress = () => {
if (pressed) {
setColour("pink");
} else {
setColour("red");
}
setPressed(!pressed);
};
return (
<Box borderColor={colour}>
<Button onPress={handlePress} />
</Box>
);
};
In the updated example we are handling the state update via the event, which is the preferable method in these situations. The same pattern applies across components - instead of listening to changes in props passed around components to update state, pass callbacks that can be used to update that state directly from an event.
Not everything has to be state
If a piece of state can be determined using props, or state the component already has access to, it probably doesn't need to be kept in component state.
const Component = () => {
const [stake, setStake] = useState(0);
const [buttonDisabled, setButtonDisabled] = useState(false);
const editStake = (newStake) => {
setStake(newStake);
if (newStake > 10) {
setButtonDisabled(true);
} else {
setButtonDisabled(false);
}
};
return (
...
)
};
In this example we can determine the value of buttonDisabled
during render using state that is already available. When setStake
is called, it will trigger a re-render, and that updated value can be used to correctly determine the value.
const Component = () => {
const [stake, setStake] = useState(0);
const buttonDisabled = stake > 10;
const editStake = (newStake) => {
setStake(newStake);
};
return (
...
)
};