Home > Software design >  I want to get 3 random data (different from each other) using UseSelector/userReducer but I can'
I want to get 3 random data (different from each other) using UseSelector/userReducer but I can'

Time:04-04

I want to get 3 random (but different from each other) user data using useSelector and display these data on the screen.but it always renders unnecessarily and I can't reach the result I wanted.Unfortunately I couldn't find where I made the mistake.

The final version of my code is as follows;

import * as React from "react";
import Avatar from "@mui/material/Avatar";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { useSelector } from "react-redux";
import "./whoToFollow.css";

export default function WoToFollow() {
  const { authReducer, userReducer } = useSelector((state) => state);
  const authUser = authReducer?.user?.userId;
  const userList = userReducer?.data;

  var arrayMyUser = [];
  console.log("arrayMyUser =>>", arrayMyUser);
  var selected = [];
  // console.log("selected =>>", selected);

  function arrayUserList(callback) {
    setTimeout(function () {
      var arrayUsers = userList?.filter((user) => user?.userId !== authUser);
      arrayUsers?.map((item) => arrayMyUser.push(item));
    }, 1000);
    callback();
  }

  function rand() {
    setTimeout(function () {
      for (var i = 0; i < 3; i  ) {
        var ran = arrayMyUser[Math.floor(Math.random() * arrayMyUser?.length)];
        console.log("ran =>> ", ran);
        if (selected.indexOf(ran) === -1) selected.push(ran);
      }
    }, 1000);
  }

  arrayUserList(rand);

  return (
    <Stack direction="row" spacing={2}>
      {selected &&
        selected?.map((p) => (
          <Box className="whotofollowavatar">
            <Avatar
              className="whotoFollowAvatar"
              alt={p?.name}
              src={p?.avatar}
            />
            <Typography variant="overline" display="block" gutterBottom>
              {p?.name   p?.surname}
            </Typography>
            <Button className="whotoFollowButton" variant="contained">
              Follow
            </Button>
          </Box>
        ))}
    </Stack>
  );
}

I tried to get three random data, but each time I got a different error. I got "undefined" for the first time, then I couldn't get the data randomly and Sometimes I didn't get any results because the data came late.. Finally, the data sometimes comes as I want, sometimes it doesn't come at all.

CodePudding user response:

you have some problems and you are doing everything really complicated, some key points to have in mind using React:

  • every piece of code besides hooks inside a function component will run on every render, that means every variable you define will have a new value on every render (except for hooks)
  • if you need to store a value between renders, use a hook (useState or useRef are the most basic)

Here is your component using the useEffect useState to store the suggestions list, (also you had a typo in the component name):

function WhoToFollow() {
  const authUser = 3; // this is from your reducer
  const userList = useRef([...dummyUserList]); // this is from your reducer, ignore the useRef, is for testing
  const [suggestionList, setSuggestionList] = useState<any>([]); // replace any with the correct type

  useEffect(() => {
    if (authUser && userList) {
      setSuggestionList(() => {
        const { current: completeUserList } = userList;
        const filteredList = completeUserList.filter(
          (user) => user?.userId !== authUser
        );
        const newSuggestionList = [];

        while (newSuggestionList.length < 3) {
          const ran =
            filteredList[Math.floor(Math.random() * filteredList?.length)];
          if (newSuggestionList.indexOf(ran) === -1)
            newSuggestionList.push(ran);
        }

        return newSuggestionList;
      });
    }
  }, [userList, authUser]);

  return (
    <div>
      userList:
      {suggestionList.map((user: any) => (
        <div>{user.name}</div>
      ))}
    </div>
  );
}

What I did:

  • store the generated list inside an useState
  • move all the logic to the useEffect and remove the functions, you don't need those
  • refactor the logic to generate 3 suggestions using a while, with the for it will not generate 3 suggestions every time, if you find a duplicated, it will not add a new one

Here is a codesandbox:

https://codesandbox.io/s/kind-silence-3e5s80?file=/src/App.tsx

CodePudding user response:

You can try this, encapsulating the function within a useEffect hook. Also i feel like you it would be best to have states for arrayMyUser, and selected. That will be the "React" way of handling things.

import * as React from "react";
import Avatar from "@mui/material/Avatar";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { useSelector } from "react-redux";
import "./whoToFollow.css";

export default function WoToFollow() {
  const { authReducer, userReducer } = useSelector((state) => state);
  const authUser = authReducer?.user?.userId;
  const userList = userReducer?.data;

  var arrayMyUser = [];
  console.log("arrayMyUser =>>", arrayMyUser);
  var selected = [];
  // console.log("selected =>>", selected);

  function arrayUserList(callback) {
    setTimeout(function () {
      var arrayUsers = userList?.filter((user) => user?.userId !== authUser);
      arrayUsers?.map((item) => arrayMyUser.push(item));
    }, 1000);
    callback();
  }

  function rand() {
    setTimeout(function () {
      for (var i = 0; i < 3; i  ) {
        var ran = arrayMyUser[Math.floor(Math.random() * arrayMyUser?.length)];
        console.log("ran =>> ", ran);
        if (selected.indexOf(ran) === -1) selected.push(ran);
      }
    }, 1000);
  }
  useEffect(() => {
    if (authUser && userList) {
      arrayUserList(rand);
    }
  }, [authUser, userList]);

  return (
    <Stack direction="row" spacing={2}>
      {selected &&
        selected?.map((p) => (
          <Box className="whotofollowavatar">
            <Avatar
              className="whotoFollowAvatar"
              alt={p?.name}
              src={p?.avatar}
            />
            <Typography variant="overline" display="block" gutterBottom>
              {p?.name   p?.surname}
            </Typography>
            <Button className="whotoFollowButton" variant="contained">
              Follow
            </Button>
          </Box>
        ))}
    </Stack>
  );
}
  • Related