0

Okay so I have this large page of code but have simplified the problem below. Basically I am creating a matching app and have this component below named "Match", it gets a list of dicts from the state and I create new lists within the Match component so that I can randomize the definitions and words. The problem I face is that in the return section I want a different styling to be rendered depending on whether the correct word and definitions where pressed. I have gotten the "randomization and check if matching" code to work correctly. The only thing wrong is that after it returns true that both the definition and word match, I can't figure out how to re-render the return so only those two items are rendered with different styling.(in the code below only the definitions will change) Below I added a simple test key when creating a new list, to be the variable that will determine the styling. Look for ---> in the code below to see important notes/code.

I have tried using useEffect and placing randomArr in the form of useEffect(),[randomArr]; but no luck and also tried using useState but to no luck received error of to many renders. Just need help making sure that when test is updated to not null that the styling changes.

import React, { Fragment } from "react";
import { useSelector } from "react-redux"; //used
import { Grid, Button } from "@mui/material";

const Match = () => {
  const items = useSelector((state) => state.posts);

  let x = null;
  const wordArr = []; //New list created to randomize list taken in from state
  const randomArr = []; //same above
  const newList = []; //same above

  // ##### new list to mix up words and defs       #### //   
  for (let i = 0; i < items.length; i++) {
    newList.push(items[i]);
    wordArr.push({ _id: items[i]._id, definition: items[i].definition });
  }
  for (let i = 0; i < items.length; i++) {
    let temp2 = wordArr[Math.floor(Math.random() * wordArr.length)]; //gets random obj

    randomArr.push({ _id: temp2._id, definition: temp2.definition, test: null }); // ----> adds Null so it renders the first option below
    wordArr.splice(wordArr.indexOf(temp2), 1); //deletes random obj so does not get called again
  }
  // ####### //

  const checkId = (id) => {
    if (x) {
      if (id._id === x) {
        console.log("Match");
        console.log(id);
        console.log(x);
        newList.pop();
        console.log(newList);
        id.test = true // ---->Changes test to something so it returns true below
      } else {
        console.log("no match");
      }
      x = null;
    } else {
      x = id._id;
    }
  };

  return (
    <div>
      <Grid container spacing={2}>
        {items.map((item, i) => (
          <Fragment key={`word${item._id}`}>
            <Grid item xs={6}>
              <Button fullWidth onClick={() => checkId(item)}>
                <SimpleCard item={item.word}></SimpleCard>
              </Button>
            </Grid>
            {randomArr[i].test ? (
              <Grid item xs={6}>
                <div> Changed</div>
              </Grid>
            ) : (
              <Grid item xs={6}>
                <Button fullWidth onClick={() => checkId(randomArr[i])}>
                  <SimpleCard item={randomArr[i].definition}></SimpleCard>
                </Button>
              </Grid>
            )}
          </Fragment>
        ))}
      </Grid>
    </div>
  );
};

export default Match;

Edit changing the checkId to use state

const [x, setX] = useState(null); 
const [x, setX] = useState(null);
  const checkId = (id) => {
    if (x) {
      if (id._ID === x) {
        console.log("Match");
        console.log(id._id);
        console.log(x);
        newList.pop();
        console.log(newList);
        id.test = true
      } else {
        console.log("no match");
      }
      setX(null);
      console.log("reset");
    } else {
      setX(id._id);
      console.log("set X");
    }
  };

[MostUpdated] Error Code

  const randomfunc = () => {
    for (let i = 0; i < items.length; i++) {
      newList.push(items[i]);
      wordArr.push({ _id: items[i]._id, definition: items[i].definition });
    }
    for (let i = 0; i < items.length; i++) {
      let temp2 = wordArr[Math.floor(Math.random() * wordArr.length)]; //gets random obj

      randomArr.push({
        _id: temp2._id,
        definition: temp2.definition,
        test: null,
      }); // ----> adds Null so it renders the first option below
      wordArr.splice(wordArr.indexOf(temp2), 1); //deletes random obj so does not get called again
    }
  };
  const [x, setX] = useState(null);

  useEffect(() => {
    randomfunc();
    console.log("test");
  });
8
  • 1
    Because you are simply declaring variables at the top level of your component and not using State there is no mechanism to trigger a rerender (and if a rerender did occur all of your variables would be redeclared as empty arrays again). Instead, those variables should be held in state in the component and the checkId should setState in order to tell react to rerender. Commented May 23, 2022 at 7:43
  • Okay so I set the checkId to use useState and it re renders the components, yet renders them in different order rather than style, code edited in original post bottom Commented May 23, 2022 at 15:49
  • 1
    Yes, the randomized arrays should also be stored in state (or at least a ref), and the randomization code should be in a useEffect with empty dependency array so that it is only called on first mount. Commented May 23, 2022 at 16:15
  • 1
    I don't have time to write a proper answer, but here is a sandbox which illustrates a minimal implementation. I've used a more concise shuffle (see: How to randomize (shuffle) a JavaScript array?), made sure to avoid mutation of state/redux source objects, and added some verbose conditional styling, as well conditional onClicks. I hope it helps clarify some concepts (the Commented May 23, 2022 at 22:52
  • 1
    Some relevant duplicates: Multiple CSS conditional classes using React and How to conditionally add or not onClick on a div in react? Commented May 23, 2022 at 22:53

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.