ihor / react-native-scalable-image

React Native Image component which scales width or height automatically to keep the original aspect ratio
https://www.npmjs.com/package/react-native-scalable-image
MIT License
315 stars 67 forks source link

React 0.74 - Update defaultProps to JavaScript default parameters. #43

Open bruce-mec opened 5 months ago

bruce-mec commented 5 months ago

After updating to React Native 0.74, the following error/warning is produced.

Support for defaultProps will be removed from function components in a future major release. 
Use JavaScript default parameters instead.

RN 0.74 RNSI 1.1.0

manssorr commented 4 months ago

I have updated the ScalableImage component to use JavaScript default parameters instead of defaultProps. Below is the patch you can use to fix this issue:

Patch File

Create a file named react-native-scalable-image+1.1.0.patch in the patches directory of your project with the following content:

diff --git a/node_modules/react-native-scalable-image/index.js b/node_modules/react-native-scalable-image/index.js
index 655e3b3..44b65ff 100644
--- a/node_modules/react-native-scalable-image/index.js
+++ b/node_modules/react-native-scalable-image/index.js
@@ -1,123 +1,125 @@
-import React, {
-    useState,
-    useEffect,
-    useRef
-} from 'react';
+import React, {useState, useEffect, useRef} from "react";

-import PropTypes from 'prop-types';
+import PropTypes from "prop-types";

-import {
-    Image,
-    TouchableOpacity,
-    ImageBackground
-} from 'react-native';
+import {Image, TouchableOpacity, ImageBackground} from "react-native";

 const resolveAssetSource = Image.resolveAssetSource;

-const ScalableImage = props => {
-    const ImageComponent = props.component
-        ? props.component
-        : props.background
-            ? ImageBackground
-            : Image;
-
-    const [scalableWidth, setScalableWidth] = useState(null);
-    const [scalableHeight, setScalableHeight] = useState(null);
-    const [image, setImage] = useState(null);
-    const mounted = useRef(false);
-
-    useEffect(() => {
-        mounted.current = true;
-
-        return () => {
-            mounted.current = false;
-        }
-    }, []);
-
-    useEffect(() => {
-        onProps(props);
-    });
-
-    useEffect(() => {
-        setImage(
-            <ImageComponent
-                {...props}
-                style={[props.style, {
-                    width: scalableWidth,
-                    height: scalableHeight
-                }]}
-            />
-        );
-    }, [scalableHeight, scalableWidth]);
-
-    const onProps = localProps => {
-        const { source } = localProps;
-        if (source.uri) {
-            const sourceToUse = source.uri
-                ? source.uri
-                : source;
-
-            Image.getSize(
-                sourceToUse,
-                (width, height) => adjustSize(width, height, props),
-                console.err
-            );
-        }
-        else {
-            const sourceToUse = resolveAssetSource(source);
-            adjustSize(sourceToUse.width, sourceToUse.height, props);
-        }
-    };
-
-    const adjustSize = (sourceWidth, sourceHeight, localProps) => {
-        const { width, height } = localProps;
-
-        let ratio = 1;
-
-        if (width && height) {
-            ratio = Math.min(width / sourceWidth, height / sourceHeight);
-        }
-        else if (width) {
-            ratio = width / sourceWidth;
-        }
-        else if (height) {
-            ratio = height / sourceHeight;
-        }
-
-        if (mounted.current) {
-            const computedWidth = sourceWidth * ratio;
-            const computedHeight = sourceHeight * ratio;
-
-            setScalableWidth(computedWidth);
-            setScalableHeight(computedHeight);
-
-            props.onSize({ width: computedWidth, height: computedHeight });
-        }
-    };
-
-    if (!props.onPress) {
-        return image;
-    }
-    else {
-        return (
-            <TouchableOpacity onPress={props.onPress}>
-                {image}
-            </TouchableOpacity>
-        );
-    }
+const ScalableImage = ({
+   component,
+   background = false,
+   onSize = (size) => {},
+   width,
+   height,
+   onPress,
+   style,
+   source,
+   ...props
+}) => {
+   const newCompinedProps = {
+       component,
+       background,
+       onSize,
+       width,
+       height,
+       onPress,
+       style,
+       source,
+       ...props,
+   };
+
+   const ImageComponent = component
+       ? component
+       : background
+       ? ImageBackground
+       : Image;
+
+   const [scalableWidth, setScalableWidth] = useState(null);
+   const [scalableHeight, setScalableHeight] = useState(null);
+   const [image, setImage] = useState(null);
+   const mounted = useRef(false);
+
+   useEffect(() => {
+       mounted.current = true;
+
+       return () => {
+           mounted.current = false;
+       };
+   }, []);
+
+   useEffect(() => {
+       onProps(newCompinedProps);
+   });
+
+   useEffect(() => {
+       setImage(
+           <ImageComponent
+               {...newCompinedProps}
+               style={[
+                   style,
+                   {
+                       width: scalableWidth,
+                       height: scalableHeight,
+                   },
+               ]}
+           />
+       );
+   }, [scalableHeight, scalableWidth]);
+
+   const onProps = (localProps) => {
+       const {source} = localProps;
+       if (source.uri) {
+           const sourceToUse = source.uri ? source.uri : source;
+
+           Image.getSize(
+               sourceToUse,
+               (width, height) => adjustSize(width, height, newCompinedProps),
+               console.err
+           );
+       } else {
+           const sourceToUse = resolveAssetSource(source);
+           adjustSize(sourceToUse.width, sourceToUse.height, newCompinedProps);
+       }
+   };
+
+   const adjustSize = (sourceWidth, sourceHeight, localProps) => {
+       const {width, height} = localProps;
+
+       let ratio = 1;
+
+       if (width && height) {
+           ratio = Math.min(width / sourceWidth, height / sourceHeight);
+       } else if (width) {
+           ratio = width / sourceWidth;
+       } else if (height) {
+           ratio = height / sourceHeight;
+       }
+
+       if (mounted.current) {
+           const computedWidth = sourceWidth * ratio;
+           const computedHeight = sourceHeight * ratio;
+
+           setScalableWidth(computedWidth);
+           setScalableHeight(computedHeight);
+
+           onSize({width: computedWidth, height: computedHeight});
+       }
+   };
+
+   if (!onPress) {
+       return image;
+   } else {
+       return <TouchableOpacity onPress={onPress}>{image}</TouchableOpacity>;
+   }
 };

 ScalableImage.propTypes = {
-    width: PropTypes.number,
-    height: PropTypes.number,
-    onPress: PropTypes.func,
-    onSize: PropTypes.func,
-    background: PropTypes.bool,
-};
-
-ScalableImage.defaultProps = {
-    background: false,
-    onSize: size => {}
+   width: PropTypes.number,
+   height: PropTypes.number,
+   onPress: PropTypes.func,
+   onSize: PropTypes.func,
+   background: PropTypes.bool,
 };

 export default ScalableImage;

How to Apply the Patch

  1. Install patch-package:
npm install patch-package
  1. Add the postinstall script in your package.json to apply patches automatically after installing packages:
{
  "scripts": {
    "postinstall": "patch-package"
  }
}
  1. Create the Patch File:

Save the above patch file content in a file named react-native-scalable-image+1.1.0.patch in the patches directory of your project.

  1. Run npm install:

This will automatically apply the patch.

By following these steps, you can resolve the deprecation warning while ensuring compatibility with future React releases.

And maybe I can make PR for this in the future.

bruce-mec commented 2 months ago

Ok I've added the patch file but I'm getting an error that it could not be parsed. react-native-scalable-image+1.1.0.patch

yarn install v1.22.22
[1/4] Resolving packages...
success Already up-to-date.
$ patch-package
patch-package 8.0.0
Applying patches...
react-native-render-html@6.3.4 ✔

**ERROR** Failed to apply patch for package react-native-scalable-image

  This happened because the patch file patches\react-native-scalable-image+1.1.0.patch could not be parsed.

  If you just upgraded patch-package, you can try running:

    cd patches\react-native-scalable-image+1.1.0.patc
    patch -p1 -i h
    npx patch-package react-native-scalable-image
    cd ../..

  Otherwise, try manually creating the patch file again.
bruce-mec commented 2 months ago

Fixed! Turned out to be a CRLF vs LF issue in the file Patch Package Issue #191

Corrected file if anyone needs it: react-native-scalable-image+1.1.0.patch