0

I am pulling down results from an API, like so:

  const [state, setState] = React.useState({

        matches: undefined,
        chosenBets: [{}]
      });


        const API = "https://api.myjson.com/bins/i461t"

      const fetchData = async (endpoint, callback) => {
        const response = await fetch(endpoint);
        const json = await response.json();
        setState({ matches: json });
      };

And rendering JSX based off it using the map() function:

export function MatchCardGroup(props) {
  return (
    <div>
      {props.matches.map((match, i) => {
        return (
          <MatchCard
            key={i}
            matchCardIndex={i}
            team_home={match.teams[0]}
            team_away={match.teams[1]}
            league_name={match.sport_nice}
            odd_home={match.sites[0].odds.h2h[0]}
            odd_draw={match.sites[0].odds.h2h[1]}
            odd_away={match.sites[0].odds.h2h[2]}
            onClick={props.onClick}
            timestamp={match.timestamp}
          />
        );
      })}
    </div>
  );
}

I then have a card which has odds on it, each odd with its own click event:

export function MatchCard(props) {
  const [state, setState] = React.useState({
    selection: {
      id: undefined
    }
  });

  const {
    timestamp,
    team_home,
    team_away,
    league_name,
    odd_away,
    odd_draw,
    odd_home,
    onClick,
    matchCardIndex,
    selection
  } = props;

  const odds = [
    {
      id: 0,
      label: 1,
      odd: odd_home || 1.6
    },
    {
      id: 1,
      label: "X",
      odd: odd_draw || 1.9
    },
    {
      id: 2,
      label: 2,
      odd: odd_away || 2.6
    }
  ];

  const handleOnClick = (odd, oddIndex) => {
    // need to changhe the selection to prop
    if (state.selection.id === oddIndex) {
      setState({
        selection: {
          id: undefined
        }
      });
      onClick({}, matchCardIndex);
    } else {
      setState({
        selection: {
          ...odd,
          team_home,
          team_away
        }
      });
      onClick({ ...odd, oddIndex, team_home, team_away, matchCardIndex });
    }
  };

  React.useEffect(() => {}, [state, props]);

  return (
    <div style={{ width: "100%", height: 140, backgroundColor: colour.white }}>
      <div>
        <span
          style={{
            ...type.smallBold,
            color: colour.betpawaGreen
          }}
        >
          {timestamp}
        </span>
        <h2 style={{ ...type.medium, ...typography }}>{team_home}</h2>
        <h2 style={{ ...type.medium, ...typography }}>{team_away}</h2>
        <span
          style={{
            ...type.small,
            color: colour.silver,
            ...typography
          }}
        >
          {league_name}
        </span>
      </div>

      <div style={{ display: "flex" }}>
        {odds.map((odd, oddIndex) => {
          return (
            <OddButton
              key={oddIndex}
              oddBackgroundColor={getBackgroundColour(
                state.selection.id,
                oddIndex,
                colour.lime,
                colour.betpawaGreen
              )}
              labelBackgroundColor={getBackgroundColour(
                state.selection.id,
                oddIndex,
                colour.lightLime,
                colour.darkBetpawaGreen
              )}
              width={"calc(33.3% - 8px)"}
              label={`${odd.label}`}
              odd={`${odd.odd}`}
              onClick={() => handleOnClick(odd, oddIndex)}
            />
          );
        })}
      </div>
    </div>
  );
}

In my App Component I am logging the returned object from the click event:

  const onClick = obj => {
    // check if obj exists in state.chosenBets
    // if it exists, remove from array
    // if it does not exist, add it to the array
    if (state.chosenBets.filter(value => value == obj).length > 0) {
      console.log("5 found.");
    } else {
      console.log(state.chosenBets, "state.chosenBets");
    }
  };

And what I want to do is this:

  1. When the user clicks an odd of any given match, add that odd to chosenBets
  2. If the user deselects the odd, remove that odd from chosenBets
  3. Only 1 odd from each of the 3 possible odds of any match can be selected at any time

Bonus points: the selected odd is selected based on the global state from App, instead of local state. This is so if I edit the array elsewhere, it should update in the UI.

Any help would be greatly appreciated, I'm lost here!

Link to Codesandbox

1 Answer 1

1

I've taken a short look at your project, and here are a few pointers to help you out:

Objects are only equal by reference.

This means that

{ id: 0, matchCardIndex: 8 } === { id: 0, matchCardIndex: 8 } 

is false, even if you expect it to be true. To compare them, you need to compare every key in the object:

value.id === obj.id && value.matchCardIndex === obj.matchCardIndex

This also affects the filter call you have in the index.tsx, so you should change the comparison there to something similar to

state.chosenBets.filter(value => value.id === obj.id && value.matchCardIndex === obj.matchCardIndex)

State should only live in one place

As you already mentioned, it would be better to keep the state in your index.tsx if it also you needed there, and don't keep it locally in the components further down the tree. I'd suggest having the components only render the state, and have handlers to change the state.

Example

Here's a fork of your code sandbox I think implements it in a way that you described: https://codesandbox.io/s/gifted-star-wg629-so-pg5gx

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, Niels. I sorted this anyways, but forgot I'd posted this here. Thanks for your help, I appreciate it! 🙏

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.