I have a settings section to my UI which keeps track of a myriad of user settings. The settings are requested from an API when the app loads, and then used in the section to populate what the user's current settings are. I am using redux for this. For example:
const Settings () => {
const dispatch = useDispatch();
const userSettings = useSelector(state => state.user.settings);
const { getNotifications } = userSettings;
return (
<form>
<label>Receive Notifications?</label>
<input
type="checkbox"
checked={getNotifications}
onClick={() => {
dispatch(
putNewUserSettings({ getNotifications: !getNotifications })
)
}}
/>
</form>
)
}
The putNewUserSettings
function registers a new action in redux, which makes an api call to update the settings from the back end. When that api call returns, redux captures that, and updates state.user.settings
, and the checkbox changes from being checked to unchecked, or vice versa. Great.
This, however, causes a delay in the UI. The user clicks the checkbox, but it doesn't actually change until the api call returns and updates the redux store. This makes for a sluggish-feeling UI. Not good!
My solution to this is to actually maintain the state of the checkbox (or whatever other form field) in local state, and when that changes, create an effect to make the api call:
const Settings () => {
const dispatch = useDispatch();
const userSettings = useSelector(state => state.user.settings);
const { getNotifications } = userSettings;
// Doubling of state, use redux value as initial value
const [getNotificationsLocal, setGetNotificationsLocal] = useState(getNotifications);
/**
* What local state changes, make call to api so that db is updated with
* new user settings
*/
useEffect(() => {
dispatch(
putNewUserSettings({ getNotifications: getNotificationsLocal })
)
}, [getNotificationsLocal])
return (
<form>
<label>Receive Notifications?</label>
<input
type="checkbox"
checked={getNotificationsLocal}
onClick={() => { setGetNotificationsLocal(!getNotificationsLocal) }}
/>
</form>
)
}
So in this second case, because the checkbox is reading from local state, when the user taps the checkbox, it immediately updates in the UI, and it has that performant feel. As a secondary effect, that change triggers a call to the API to 'officially' update the setting in a more global sense. (I do make use of a handy hook called useDidMountEffect to avoid running the API call on mount, as it would be unecessary to call the API to set the settings value to what it already is.)
Is this bad practice? I find myself doing this all over in an app because the api is a touch slow and causing for slow UI. Is this some kind of anti-pattern that will cause more problems I'm not foreseeing?