PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

preface

Yesterday attended the annual meeting of the company, obviously I haven’t, what awards what “good people” front-end engineer has nothing to do with us, or I will not write the article here, and so on, why want to use “we”, here [question. JPG], front-end engineer should be review less than “excellent staff”, [play face. PNG], if you have a friend, Feel free to share in the comments section, How do Front-end Engineers Make Top Employees?

Let’s start with this year’s corporate awards

  • First prize iPhone13 10
  • Second prize Apple Watch 30
  • 50 grade iii AirPos

No special prize, feeling the winning rate is quite high, so how many people participate? There are 700 people? How come there are so many people, how do I remember that the company only has about 350 people, 2021 hired so many people? And then, this lottery program is bought, about 5000+ I don’t remember the specific, I was wondering if this program is not good for internal development? So you can buy it? Forget it, don’t tangle, together to see how the lottery program to achieve it!

Lucky draw program

The leader said to begin to roll the screen, the leader shouted stop stop, so a lottery form, we all understand.

Prize data JSON

Let’s define a JSON representation of the prize

[
  {
    name: "First Prize",
    count: 10,
    img: "https://img13.360buyimg.com/cms/jfs/t1/208697/10/617/143853/61413ae6E577772f8/fc01a7a528f9c531.png",
    time: 10,
  },
  {
    name: "Second prize",
    count: 30,
    img: "https://img11.360buyimg.com/cms/jfs/t1/203838/28/10178/146961/615ff266E8c0f9045/78bfc03faf8b1e2d.png",
    time: 5,
  },
  {
    name: "Third prize",
    count: 50,
    img: "https://img13.360buyimg.com/cms/jfs/t1/85541/32/9875/160522/5e12bfe2Ed83e51f5/934dbc9de37038f2.png",
    time: 5,},];Copy the code

Time is the number of lucky draws and count is the number of prizes

Simulated users

Here we use the famous faker.js which is currently maintained by the community, starting with the installation package

npm install @faker-js/faker -D
Copy the code

Generate 700 users

import faker from "@faker-js/faker";
faker.setLocale("zh_CN");

const users = new Array(700).fill(null).map((item, index) = > ({
    id: index + 1.name: faker.name.lastName() + faker.name.firstName(),
  }));
Copy the code

The ID needs to be unique, because it might have the same name

JS lottery implementation

That’s a list of randomly selected users

const randomCountUser = (list, count) = > {
  let shows = [];
  for (let index = 0; index < count; index++) {
    const random = Math.floor(Math.random() * list.length);
    shows.push(list[random]);
    list[random] = list[list.length - 1];
    list.length--;
  }
  return shows;
};
Copy the code

  • Why not splice?

    • Most people start out thinking thatspliceThis is a very correct and intuitive understanding. But be carefulspliceIs a performance intensive operation, if the lottery pool size is large will significantly affect performance
  • Why assign a value to list[random] and then decrease the length by one?

    • We need to strip out the winning users, fill in the users at the end of the array, and then subtract the entire array length by one, so that when we go through the next time, we have a new array, and we have the least amount of change to the entire array, and the least performance cost.

The React to realize

Create a project using create-react-app and configure tailwindCSS

npx create-react-app my-project
npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p
Copy the code

Let’s define some states

// How many prizes are currently drawn
const [current, setCurrent] = useState(awards.length - 1);
const award = awards[current];
// Whether to end
const [over, setOver] = useState(false);
// The current number of times
const [currentTime, setCurrentTime] = useState(0);
// Yes, it is
const goingRef = useRef(false);
// Users who have won the lottery have user data filtering
const [winners, setWinners] = useState([]);
// Output the winning result
const [result, setResult] = useState({});
// Display the user interface
const [showUsers, setShowUsers] = useState([]);
// Take several at a time
const  currentNumber = award.count / award.time;
Copy the code

Press Start to pause the implementation

  const toggle = () = > {
    if (over) {
      return;
    }
    if(! goingRef.current) {if (award.count > currentWinNumber) {
        const winnerIds = winners.map((w) = > w.id);
        let others = winnerIds.length
          ? users.filter((u) = >! winnerIds.includes(u.id)) : users; goingRef.current =setInterval(() = > {
          setShowUsers(randomCountUser(others, currentNumber));
        }, 200);
      } else {
        if (current > 0) {
          setCurrentTime(0);
          setShowUsers([]);
          setCurrent(current - 1);
        } else {
          setOver(true); }}}else {
      clearInterval(goingRef.current);
      goingRef.current = false;
      setWinners([...winners, ...showUsers]);
      setResult((prev) = > {
        let sumWinners = prev[award.name] || [];
        sumWinners = sumWinners.concat(showUsers);
        return {
          ...prev,
          [award.name]: sumWinners,
        };
      });
      setCurrentTime(currentTime + 1); }};Copy the code

Using a tailwind CSS

Using the grid place-items-stretch class, you can spread child elements across the entire area

conclusion

That’s it. So fast? Before we get to 100 lines of code, the boss bought a lottery program, and that’s it? Is there any quota? Ok, let’s add another quota

How to win 100% of the lottery,

Add internal parameters


const suerData={
    'First Prize': [701.702]}Copy the code

701 and 702 are the two users I added later, and I hope these two users will win the first prize

Custom hooks

In fact, the core of the lottery is random number, we only need to define input and output parameters, we do not care about the parameters in the lottery process, so we can extract a custom hook.

The input

  • Users All users
  • Awards All Awards
  • SureData internal quota

The output

  • Toggle starts or stops
  • Award The award currently drawn
  • ShowUsers Indicates the user to be displayed
  • Result Winning the lottery
const reducer = (state, payload) = >({... state, ... payload });function useLottery(users, awards, sureData = {}) {
  // Yes, it is
  const goingRef = useRef(false);
  const [state, setState] = useReducer(reducer, {
    current: awards.length - 1.over: false.// Whether to end
    currentTime: 0.// The current number of times
    winners: [].// Users who have won the lottery have user data filtering
    result: [].// Output the winning result
    showUsers: [].// Display the user interface
    sure: sureData,
  });

  const { current, over, currentTime, winners, result, showUsers, sure } =
    state;

  // How many prizes are currently drawn
  const award = awards[current];

  // Take several at a time
  const currentNumber = award.count / award.time;
  //currentWinNumber
  const currentWinNumber = currentTime * currentNumber;

  const toggle = () = > {
    if (over) {
      return;
    }
    if(! goingRef.current) {if (award.count > currentWinNumber) {
        const winnerIds = winners.map((w) = > w.id);
        let others = winnerIds.length
          ? users.filter((u) = >! winnerIds.includes(u.id)) : users; goingRef.current =setInterval(() = > {
          setState({
            showUsers: randomCountUser(others, currentNumber),
          });
        }, 200);
      } else {
        if (current > 0) {
          setState({
            currentTime: 0.showUsers: [].current: current - 1}); }else {
          setState({
            over: true}); }}}else {
      clearInterval(goingRef.current);
      goingRef.current = false;
      // Finally display the user, in order to be able to modify directly
      let finailyShowUsers = showUsers;
      letfinailySureData = { ... sure };// If there is a built-in quota logic
      if (Array.isArray(sure[award.name])) {
        finailyShowUsers = showUsers.map((p, index) = > {
          let sureUser;
          sureUser = sure[award.name][index]
            ? users.find((u) = > u.id === sure[award.name][index])
            : undefined;
          if (sureUser) {
            finailySureData[award.name] = sure[award.name].filter(
              (id) = >id ! == sureUser.id );return sureUser;
          } else {
            returnp; }}); }let sumWinners = result[award.name] || [];
      sumWinners = sumWinners.concat(finailyShowUsers);

      setState({
        winners: [...winners, ...finailyShowUsers],
        showUsers: finailyShowUsers,
        currentTime: currentTime + 1.sure: finailySureData,
        result: {... result, [award.name]: sumWinners, }, }); }};return {
    toggle,
    result,
    award,
    showUsers,
  };
}
Copy the code

test

The use of hooks

Const {toggle, award, showUsers, result} = useLottery(Users, Awards, {third prize: [701, 702],});Copy the code

Release NPM package

Of course, we can release a NPM package for this hook, and maybe we will develop a mobile lottery page in the future. We can share this lottery logic, just rewrite the view part. Before sending the package, we need to test this hook. I’m using @testing-library/react-hooks. I won’t expand on them here, but I’ll save the article “How to test React hooks?”

The last

Through this article I learned

  1. Release a React hooks NPM package
  2. Automatically publish NPM packages using github Action
  3. Deploy the preview page using Github Pages
  4. All lottery programs are random numbers
  5. There may be a quota in the program

Lucky draw plus (additional quota) is also given to you for free. I hope you enjoy it.

  • IO /react-use-l maqi1520. Github. IO /react-use-l…
  • NPM: www.npmjs.com/package/@ma…
  • Making: github.com/maqi1520/re…

At the end of the article, please like 👍🏻. I hope this article has been helpful to you. You can also refer to my previous articles or share your thoughts and experiences in the comments section.