Skip to content

Instantly share code, notes, and snippets.

@niraj-khatiwada
Created October 26, 2022 14:05
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niraj-khatiwada/0dd5bdac57b3b52cda0d1e4952983694 to your computer and use it in GitHub Desktop.
Save niraj-khatiwada/0dd5bdac57b3b52cda0d1e4952983694 to your computer and use it in GitHub Desktop.
function Favorite({
postId = null,
isLiked: _isLiked = false,
numberOfLikes: _numberOfLikes = 0,
}) {
const [isLiked, setIsLiked] = React.useState(_isLiked);
const [numberOfLikes, setNumberOfLikes] = React.useState(_numberOfLikes ?? 0);
const likeDebounceRef = React.useRef();
const lastIsLikedStateRef = React.useRef(_isLiked);
const lastNumberOfLikesStateRef = React.useRef(_numberOfLikes ?? 0);
const [likePost] = useMutation(LIKE_POST, {
variables: {
postId,
},
});
const [unlikePost] = useMutation(UNLIKE_POST, {
variables: {
postId,
},
});
const likeUnlikePost = React.useCallback(
async (toBeLiked = true, errorCB = () => null) => {
try {
const {data} = await (toBeLiked ? likePost() : unlikePost());
const response = data?.[toBeLiked ? 'likePost' : 'unlikePost'];
const isSuccess = response?.success;
const code = response?.code;
if (!isSuccess) {
if (code === 'POST_ALREADY_LIKED') {
setIsLiked(true);
lastIsLikedStateRef.current = true;
} else if (code === 'POST_NOT_LIKED') {
setIsLiked(false);
lastIsLikedStateRef.current = false;
} else {
errorCB();
}
}
} catch (_) {
errorCB();
}
},
[likePost, unlikePost],
);
const handleLikeUnlike = React.useCallback(() => {
let lastState = false;
setIsLiked(preState => {
lastState = preState;
setNumberOfLikes(previousLikes =>
lastState ? previousLikes - 1 : previousLikes + 1,
);
return !lastState;
});
lastIsLikedStateRef.current = !lastState;
lastNumberOfLikesStateRef.current = lastState
? lastNumberOfLikesStateRef.current - 1
: lastNumberOfLikesStateRef.current + 1;
if (likeDebounceRef.current) {
clearTimeout(likeDebounceRef.current);
}
likeDebounceRef.current = setTimeout(() => {
likeUnlikePost(!lastState, () => {
setIsLiked(lastState);
lastIsLikedStateRef.current = lastState;
setNumberOfLikes(previousLikes =>
lastState ? previousLikes.current + 1 : previousLikes.current - 1,
);
lastNumberOfLikesStateRef.current = lastState
? previousLikes + 1
: previousLikes - 1;
});
}, 300);
}, [likeUnlikePost]);
React.useEffect(() => {
if (_isLiked !== lastIsLikedStateRef.current) {
setIsLiked(_isLiked);
lastIsLikedStateRef.current = _isLiked;
}
}, [_isLiked]);
React.useEffect(() => {
if (_numberOfLikes !== lastNumberOfLikesStateRef.current) {
setNumberOfLikes(_numberOfLikes);
lastNumberOfLikesStateRef.current = _numberOfLikes;
}
}, [_numberOfLikes]);
React.useEffect(
() => () => {
clearTimeout(likeDebounceRef.current);
},
[],
);
return (
<TouchableOpacity
onPress={handleLikeUnlike}>
<Icon
name="like"
tint={isLiked ? colors.red : colors.darkGrey}
size={25}
/>
<Text>
{formatDigits(numberOfLikes) ?? ''}
</Text>
</TouchableOpacity>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment