Repository: grommet/grommet (JavaScript)

Issue:
Image component keeping previous props
I have in an Image component 'src' and 'fallback' props. Since as first time the src is undefined (''), when a value is assigned to the src, it does not change display. I had to create two Image components, each with a different key as turnaround to the issue. I will show.

### Expected Behavior

I would expect that I have only to declare only one Image component with a `src={image_source}` props that will be assigned dynamically and the component should be capable to reload itself or recognize that there´s a valid src and display it.

### Actual Behavior

As of now, it seems that it keeps the values of initial props (I don't understand how) and do not respond to dynamic changes to the props.

### Steps to Reproduce

To reproduce, 
create a component that after 2 seconds it will assign a valid value to the source, it will maintain the value in the fallback:

```
<Image {...{
    fill: 'horizontal',
    fallback: fallback_img, 
    src: img_src,
}}/>
```

Instead if you do as the next part, it will work as expected: 
```
const [MainImage, setMainImage] = useState<undefined | ReactElement>()
if (img_src) {
      setMainImage(
        <Image {...{
          key: 'main_image_with_src',
          fallback: fallback_img, 
          src: img_src,
        }}/>
      )
    } else {
      setMainImage(
        <Image {...{
          key: 'main_image_no_src',
          fill: 'horizontal',
          fallback: fallback_img, 
          src: img_src,
        }}/>
      )
    }
return (<>{ MainImage }</>)

```
### Your Environment

- Grommet version: 2.17.4
- Browser Name and version: chrome Version 92.0.4515.107 (Official Build) (64-bit)
- Operating System and version (desktop or mobile): ubuntu 20.0.4, desktop, Node 14

Hope it's clear. Thanks! :)


Discussion:
Can I work on this?
@jlaluces123 have you already started working on this?
Hey @Spectre-ak absolutely! @jcfilben I was currently on the research phase of this issue so I wouldn't mind handing it over, great to see the work being done!
@jcfilben , I've created a PR for this issue here [Fixes Image component keeping previous props](https://github.com/grommet/grommet/pull/5650)



Patch:
diff --git a/src/js/components/Image/Image.js b/src/js/components/Image/Image.js
index 02ecf1300f4..c3b8055a6ab 100644
--- a/src/js/components/Image/Image.js
+++ b/src/js/components/Image/Image.js
@@ -4,16 +4,27 @@ import { ImagePropTypes } from './propTypes';
 
 const Image = forwardRef(
   ({ a11yTitle, fallback, onError, opacity, fill, src, ...rest }, ref) => {
-    const [imageMissing, setImageMissing] = useState(false);
-    const handleError = (event) => {
-      if (onError) {
+    const [isFallbackInUse, setFallbackInUse] = useState(false);
+    
+    const handleError = (event)=>{
+      if (onError)
         onError(event);
+      if (!isFallbackInUse && fallback && fallback !== "") {
+        // eslint-disable-next-line no-param-reassign
+        event.target.src=fallback;
+        setFallbackInUse(true);
       }
-      setImageMissing(true);
     };
+
+    const handleOnLoad = () => {
+      setFallbackInUse(false);
+    };
+
     const extraProps = {
       onError: (onError || fallback) && handleError,
+      onLoad : handleOnLoad,
     };
+
     return (
       <StyledImage
         aria-label={a11yTitle}
@@ -22,7 +33,7 @@ const Image = forwardRef(
         ref={ref}
         opacityProp={opacity}
         fillProp={fill}
-        src={!imageMissing ? src : fallback}
+        src={src === undefined ? "" : src}
       />
     );
   },


Test patch:
diff --git a/src/js/components/Image/__tests__/Image-test.js b/src/js/components/Image/__tests__/Image-test.js
index 07a0bcb2a85..ca59a2bd251 100644
--- a/src/js/components/Image/__tests__/Image-test.js
+++ b/src/js/components/Image/__tests__/Image-test.js
@@ -1,5 +1,12 @@
-import React from 'react';
-import { act, cleanup, fireEvent, render } from '@testing-library/react';
+import React, { useState } from 'react';
+import { 
+  act, 
+  cleanup, 
+  fireEvent, 
+  render, 
+  screen,
+} from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
 import { axe } from 'jest-axe';
 import 'jest-styled-components';
 import 'jest-axe/extend-expect';
@@ -7,6 +14,7 @@ import 'regenerator-runtime/runtime';
 
 import { Grommet } from '../../Grommet';
 import { Image } from '..';
+import { Button } from '../../Button';
 
 const opacityTypes = ['weak', 'medium', 'strong', '0.3', true, false];
 const SRC =
@@ -98,3 +106,38 @@ test('Image onError', () => {
 
   expect(onError).toHaveBeenCalledTimes(1);
 });
+
+test('Image fallback', async () => {
+  const onError = jest.fn();
+  const fallbackImage = "https://v2.grommet.io/assets/IMG_4245.jpg";
+  const regularImage = "https://v2.grommet.io/img/stak-hurrah.svg";
+
+  const Test = () => {
+    const [imgSrc, setImgSrc] = useState("");
+    return (
+      <Grommet>
+        <Image
+          fill="horizontal"
+          fallback={fallbackImage}
+          src={imgSrc}
+          alt="test"
+          onError={onError}
+        />
+        <Button label="Update Image" onClick={() => {
+          setImgSrc(regularImage);
+        }} />
+      </Grommet>
+    );
+  };
+
+  const { getByAltText } = render(<Test />);
+  
+  fireEvent(getByAltText("test"), new Event('error'));
+  let imgSrc = screen.getByRole("img").src;
+  expect(imgSrc).toEqual(fallbackImage);
+
+  userEvent.click(screen.getByRole("button", {name: /Update Image/i}));
+  imgSrc= screen.getByRole("img").src;
+  expect(imgSrc).toEqual(regularImage);
+
+});