css animation fires as select event change fires react

Viewed 34

i'm trying to make a react app, Now I have a select input, with some Pokemons, and I need to make it so that whenever the select is changed (= the pokemon is changed), the pokemon sprite will do a little shake animation. For now I only have a sprite that changes and an audio that plays whenever the select value changes. how can accomplish this? I've tried to change its style with select onChange with styled-components but i can't get it to work, the animation only fire when the page is loaded. This is my code for now:
Select.ts:

import { closest } from "fastest-levenshtein";
import React, { useState } from "react";
import { cries, pokemons } from "../data";
import styled from "styled-components";
import { Img, ani } from "../styles";

function Select() {
  const [src, setSrc] = useState(require("../data/sprites/bulbasaur.png"));
  const opts: { label: string; value: string }[] = [];
  for (let i = 0; i < pokemons.length; i++) {
    opts.push({
      label: pokemons[i][0].toUpperCase() + pokemons[i].slice(1),
      value: pokemons[i],
    });
  }
  return (
    <div>
      <div>
        <select
          onChange={(evt) => {
            setSrc(require(`../data/sprites/${evt.target.value}.png`));
            const str = closest(evt.target.value, cries);
            const res = new Audio(require(`../data/cries/${str}`));
            res.volume = 0.2;
            res.play();
            styled(Img)`
              margin-left: 2.5em;
              animation: ${ani};
            `;
          }}
        >
          {opts.map(({ label, value }) => (
            <option key={value} label={label} value={value}></option>
          ))}
        </select>
      </div>
      <Img src={src} alt="" className="sprite" />
    </div>
  );
}

export default Select;

img.styled.ts:

import styled, { css } from "styled-components";
import { shake } from "./shake.stiled";

const ani = css(["", " 0.3s linear"] as any as TemplateStringsArray, shake);
const Img = styled.img`
  margin-left: 2.5em;
  animation: ${ani};
`;

export { Img, ani };

Thank you!

1 Answers

I believe that instead of declaring the src state in this component, putting the state in the parent component and passing setSrc as a prop to this component will help you. So in this component onChange={() => setSrc(newVal)} where setSrc is passed to the Select component as a prop.

OR, I would consider storing evt.target.value as a state, and onChange, update that value.

const [chosenImg, setChosenImg] = useState()
const [src, setSrc] = useState(require("../data/sprites/bulbasaur.png"));

useEffect(() => {
setSrc(require(`../data/sprites/${chosenImg}.png`))

}, [chosenImg]);

then:

onChange={()=> setChosenImg(evt.target.value)}
Related