Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does <SvgUri /> component support cache? #1328

Closed
hakkikonu opened this issue Mar 30, 2020 · 8 comments
Closed

Does <SvgUri /> component support cache? #1328

hakkikonu opened this issue Mar 30, 2020 · 8 comments
Labels

Comments

@hakkikonu
Copy link

Does <SvgUri /> component support cache like react native's <Image /> component?

For example I'm using cache for my remote png files like

<Image
     source={{
     uri: "https://example.com/image.png",
     cache: 'force-cache',
     }}
/>

@msand
Copy link
Collaborator

msand commented Mar 30, 2020

It uses fetch provided by react-native, so it respects the http protocol and the http cache related headers as is. If you want something more than that, I'd recommend copying the code from SvgUri and modify it to your needs.

@stale
Copy link

stale bot commented May 29, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.

@stale stale bot added the stale label May 29, 2020
@27leaves
Copy link

I also needed caching and solved it like this:

// CachedSVGUri.js
import React, {Component} from 'react';
import {SvgFromXml} from 'react-native-svg';
import SVGCacheService from '../services/storage/SVGCacheService';

export async function fetchCached(uri) {
    const cached = await SVGCacheService.getSvg(uri);
    if (cached) {
        return cached;
    } else {
        const response = await fetch(uri);
        const svg = await response.text();
        SVGCacheService.setSvg(uri, svg);
        return svg;
    }
}

export default class CachedSvgUri extends Component {
    state = {xml: null};
    componentDidMount() {
        this.fetch(this.props.uri);
    }
    componentDidUpdate(prevProps) {
        const {uri} = this.props;
        if (uri !== prevProps.uri) {
            this.fetch(uri);
        }
    }
    async fetch(uri) {
        try {
            this.setState({xml: uri ? await fetchCached(uri) : null});
        } catch (e) {
            console.error(e);
        }
    }
    render() {
        const {
            props,
            state: {xml},
        } = this;
        return <SvgFromXml xml={xml} override={props} />;
    }
}
// SVGCacheService.js
import AsyncStorage from '@react-native-community/async-storage';

const ASYNC_STORAGE_KEY = 'svg-cache';

let data = null;

const loadData = async () => {
    const defaultData = {
        svgs: {},
    };

    const result = await AsyncStorage.getItem(ASYNC_STORAGE_KEY);
    data = result ? await JSON.parse(result) : defaultData;
    data = {...defaultData, ...data};
};

export default class SVGCacheService {
    static async setSvg(uri, svg) {
        const oldData = data || {};

        const newData = {
            ...oldData,
            svgs: {
                ...oldData.svgs,
                [uri]: svg,
            },
        };

        data = newData;

        await AsyncStorage.setItem(ASYNC_STORAGE_KEY, JSON.stringify(newData));
    }

    static async getSvg(uri) {
        if (data === null) await loadData();
        return data.svgs[uri];
    }
}

@danyasnov
Copy link

@creat-or nice solution
but storing svg strings in an object can create a memory leak

@27leaves
Copy link

@danyasnov hey there!
thank you for your answer and the hint with the memory leak. do you know why this is the case and how you could test for that?
thank you!

@WoLewicki
Copy link
Member

Since the solution provided by @27leaves seems like a good option, I believe we can close this issue. Feel free to comment here if something is wrong and we can always reopen it then.

@sovetski
Copy link

sovetski commented Feb 18, 2024

Same problem here, maybe @27leaves's solution works, but as @danyasnov said, it is not an optimal solution.
This kind of functionality should be implemented in the library itself, which application will fetch X time the same SVG? Generally you do the fetch the first time and that's all...

@WoLewicki as you closed the issue, if for you the @27leaves's solution is fine, maybe you can implement him code in the library?

Thanks


After some hours, I found this package which works very well: https://docs.expo.dev/versions/latest/sdk/image
If you're installing this in a bare React Native app, you should also follow these additional installation instructions.

By default, it includes a cache and store it in the "disk", you can change if you want with: https://docs.expo.dev/versions/latest/sdk/image/#cachepolicy

A simple change will optimize your code and application, like:

<SvgUri width="50" height="50" uri="url here" />

to

<Image
   style={{
    width: 50,
    height: 50,
  }}
  source="url here"
  cachePolicy="memory-disk"
/>

And off course

npm remove react-native-svg

@kravchenko-anton
Copy link

kravchenko-anton commented Apr 28, 2024

const [svgContent, setSvgContent] = useState<string | null>(null)
	useLayoutEffect(() => {
		const getFromAsyncStorageSvg = async () => {
			const svg = await AsyncStorage.getItem('svg' + svgUri)
			if (svg) {
				console.log('svg from async storage ' + svgUri)
				setSvgContent(svg)
				return
			} else {
				const svg = await fetch(getFileUrl(svgUri)).then(response =>
					response.text()
				)
				if (!svg) return
				await AsyncStorage.setItem('svg' + svgUri, svg)
				console.log('svg from fetch ' + svgUri)
				return svg
			}
		}
		getFromAsyncStorageSvg()
	}, [svgUri])
	
<SvgXml
			xml={svgContent}
			onError={() => AsyncStorage.removeItem('svg' + svgUri)}
		/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants