Skip to content

iamboliver/react-simple-votes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

react-simple-votes

A simple React hook for like/dislike voting. Works out of the box with localStorage, or connect your own API.

npm License


✨ Features

  • Zero Config - Works immediately with localStorage
  • API Ready - Just add two URLs to connect your backend
  • Optimistic Updates - UI updates instantly, syncs in background
  • Vote Tracking - Remembers user votes, prevents duplicates
  • Vote Changing - Users can switch from like to dislike
  • TypeScript - Full type support included

📦 Installation

npm install react-simple-votes

🚀 Quick Start

import { useVotes } from 'react-simple-votes';

function LikeButton({ itemId }: { itemId: string }) {
  const { votes, userVotes, vote } = useVotes();

  const hasLiked = userVotes[itemId] === 'like';
  const hasDisliked = userVotes[itemId] === 'dislike';

  return (
    <div>
      <button
        onClick={() => vote(itemId, 'like')}
        disabled={hasLiked}
        style={{ opacity: hasLiked ? 1 : 0.6 }}
      >
        👍 {votes[itemId]?.likes || 0}
      </button>
      <button
        onClick={() => vote(itemId, 'dislike')}
        disabled={hasDisliked}
        style={{ opacity: hasDisliked ? 1 : 0.6 }}
      >
        👎 {votes[itemId]?.dislikes || 0}
      </button>
    </div>
  );
}

🔌 Connect Your API

To persist votes across users, provide your API endpoints:

const { votes, userVotes, vote } = useVotes({
  fetchUrl: 'https://api.example.com/votes',
  submitUrl: 'https://api.example.com/vote',
});

Expected API Format

GET /votes - Fetch all votes

{
  "item-id-1": { "likes": 42, "dislikes": 3 },
  "item-id-2": { "likes": 15, "dislikes": 8 }
}

POST /vote - Submit a vote

Request body:

{
  "itemId": "item-id-1",
  "voteType": "like",
  "previousVote": "dislike"
}

Response:

{ "likes": 43, "dislikes": 2 }

⚙️ Options

useVotes({
  fetchUrl?: string;    // GET endpoint for fetching votes
  submitUrl?: string;   // POST endpoint for submitting votes
  storageKey?: string;  // localStorage key prefix (default: 'react-simple-votes')
});

📋 API Reference

useVotes(options?)

Returns:

Property Type Description
votes VotesMap All vote counts: { [itemId]: { likes, dislikes } }
userVotes UserVotesMap User's votes: { [itemId]: 'like' | 'dislike' }
vote (itemId, voteType) => Promise Submit a vote
isLoading boolean Loading state
error string | null Error message

Types

type VoteType = 'like' | 'dislike';

interface VoteData {
  likes: number;
  dislikes: number;
}

interface VotesMap {
  [itemId: string]: VoteData;
}

interface UserVotesMap {
  [itemId: string]: VoteType;
}

🎨 Example: Styled Buttons

import { useVotes } from 'react-simple-votes';

function VoteButtons({ itemId }: { itemId: string }) {
  const { votes, userVotes, vote, isLoading } = useVotes();

  const itemVotes = votes[itemId] || { likes: 0, dislikes: 0 };
  const userVote = userVotes[itemId];

  return (
    <div style={{ display: 'flex', gap: '8px' }}>
      <button
        onClick={() => vote(itemId, 'like')}
        disabled={isLoading || userVote === 'like'}
        style={{
          padding: '8px 16px',
          background: userVote === 'like' ? '#22c55e' : '#f0f0f0',
          color: userVote === 'like' ? 'white' : 'black',
          border: 'none',
          borderRadius: '20px',
          cursor: userVote === 'like' ? 'default' : 'pointer',
        }}
      >
        👍 {itemVotes.likes}
      </button>
      <button
        onClick={() => vote(itemId, 'dislike')}
        disabled={isLoading || userVote === 'dislike'}
        style={{
          padding: '8px 16px',
          background: userVote === 'dislike' ? '#ef4444' : '#f0f0f0',
          color: userVote === 'dislike' ? 'white' : 'black',
          border: 'none',
          borderRadius: '20px',
          cursor: userVote === 'dislike' ? 'default' : 'pointer',
        }}
      >
        👎 {itemVotes.dislikes}
      </button>
    </div>
  );
}

📄 License

MIT License - feel free to use in your own projects!

About

A simple React hook for like/dislike voting. Works out of the box with localStorage, or connect your own API.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors