Back

Technologies:

javascriptjavascript
reactjsreactjs
avatar
Tolerim
23 days ago

How can I prevent React-Redux-Reducer from saving the same array element from the API in the redux state when the user clicks?

My task involves storing data obtained from an API in a Redux state, which will then be displayed on different pages. The reducer code that I am using for this purpose is:

const INIT_STATE = {
  movies: [],
};

export const moviereducer = (state = INIT_STATE, action) => {
  switch (action.type) {
    case "ADD_MOVIE":
      return {
        movies: [action.payload],
      };
    default:
      return state;
  }
};
In order to obtain this data, I am making use of a hero component, which calls the API and maps the data into cards. Here's the component code:

const Hero = () => {
  const [data, setData] = useState([]);
  const Dispatch = useDispatch();

  const fetchData = () => {
    return axios
      .get("https://api.tvmaze.com/search/shows?q=all")
      .then((response) => setData(response.data));
  };

  useEffect(() => {
    fetchData();
  }, []);

  const handleClick = (ele) => {
    Dispatch(ADD_MOVIE(ele));
  };

  return (
    <div className="heroWrap">
      <div className="cardWrap">
        {data &&
          data.map((ele, id) => {
            return (
              <Card key={id} style={{ width: "18rem" }}>
                <Card.Img variant="top" src={ele.show.image.medium} />
                <Card.Body>
                  <Card.Title>{ele.show.name}</Card.Title>
                  <Card.Text>Genres: {ele.show.genres + ","}</Card.Text>
                  <Button onClick={() => handleClick(ele)} variant="primary">
                    <Link className="text-white" to="/detail">
                      Read More
                    </Link>
                  </Button>
                </Card.Body>
              </Card>
            );
          })}
      </div>
    </div>
  );
};
However, regardless of which button I click, it only saves the same data in my Redux state. Here is an example of the data obtained from the API:

image1

And here is what is currently being saved in my Redux state:

image2

Edit: Although I am now able to store the correct state, I am facing a new issue - I am unable to render the image that I have stored in my Redux state.

This is the component in which I want to render the data:

image3

And this is the data that I am getting from my state:

image4

Answers(2)
avatar
Vogi
22 days ago
Verified Answer
It seems that you are trying to store data obtained from an API in a Redux state. The code you have provided seems to be correct. However, it is only storing the last element of the array in your Redux state. This is because you are overwriting the previous state with the new one every time you dispatch the action. To fix this issue, you can use the spread operator to copy the previous state and add the new data to it. Here's how you can modify your reducer code:
const INIT_STATE = {
  movies: [],
};

export const moviereducer = (state = INIT_STATE, action) => {
  switch (action.type) {
    case "ADD_MOVIE":
      return {
        movies: [...state.movies, action.payload],
      };
    default:
      return state;
  }
};
This will add the new data to your existing state instead of overwriting it. Regarding your second issue of not being able to render the image that you have stored in your Redux state, it seems that you are trying to access the image using the wrong key. In your component code, you are trying to access ele.show.image.medium, but in your Redux state, the key is image. You can modify your component code as follows:
<Card.Img variant="top" src={ele.image} />
This should render the image correctly. I hope this helps! Let me know if you have any further questions.

Sources

Storing Data From API with Redux in React Native AppsHow do I access store state in React Redux? - Stack OverflowQuick Guide for Fetching API Data Using React Redux and Hooks ... - Mediumreactjs - Retrieve data from API using Redux - Stack OverflowHow to fetch data through api in redux? - Stack Overflow
avatar
Tolerim
23 days ago
The reason you are only storing the same data in your redux state no matter which button you click on is because you are replacing the entire movies array with the new movie each time you dispatch the "ADD_MOVIE" action. Instead, you need to add the new movie to the existing array. Change your case "ADD_MOVIE" block in your reducer to:
return {
    movies: [...state.movies, action.payload],
  };
This will spread the existing movies array and add the new movie as a new element. Regarding your new problem of not being able to render the image that you have stored in your redux state, it seems like the issue might be with the way you are trying to access it. It looks like you are trying to access the image using props.movie.show.image.medium, but based on your state structure, the correct way to access the image would be props.movie.image.medium. Try changing this and see if it works:
;