From 91f7ed2f347259da93da5edc3d6380311675835b Mon Sep 17 00:00:00 2001 From: Alexis Puga Date: Tue, 9 Nov 2021 17:17:30 -0600 Subject: [PATCH 1/5] feat: load flags asynchronously Import flags asynchronously inside a useEffect hook, and set the Image source if component is mounted, with the help of a useState hook. Remove ./flags import from the top. --- index.js | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 86940fe..90a2c79 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ // @flow -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { Image } from 'react-native'; -import * as flags from './flags'; type Props = { size: 16 | 24 | 32 | 48 | 64, @@ -12,12 +11,33 @@ type Props = { }; const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { - const flag = flags[type][`icons${size}`][code]; - const unknownFlag = flags[type][`icons${size}`]['unknown']; + // @TODO Set an initial value. + const [source, setSource] = useState(); + + // Load flags asynchronously. + useEffect(() => { + let isMounted = true; + + (async () => { + const flags = await import('./flags'); + const flag = flags[type][`icons${size}`][code]; + const unknownFlag = flags[type][`icons${size}`]['unknown']; + + if (isMounted) { + setSource(flag || unknownFlag); + } + })(); + + return () => { + // Anti-pattern. + // @TODO Abort import instead. + isMounted = false; + }; + }, [type, size, code, setSource]); return ( ); From a75c3c9de7a1cb4cc0dc70618278950d0d6fc1e9 Mon Sep 17 00:00:00 2001 From: Alexis Puga Date: Tue, 9 Nov 2021 18:23:26 -0600 Subject: [PATCH 2/5] refactor: get flags using a function Move duplicated code to a new function called getFlag. --- index.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 90a2c79..3a79131 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,16 @@ type Props = { style?: any, }; +const getFlag = (flags: {}, { type, size, code }: { + type: string, + size: number, + code: string +}) => { + const sizeKey = `icons${size}`; + + return flags[type][sizeKey][code]; +}; + const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { // @TODO Set an initial value. const [source, setSource] = useState(); @@ -20,8 +30,8 @@ const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { (async () => { const flags = await import('./flags'); - const flag = flags[type][`icons${size}`][code]; - const unknownFlag = flags[type][`icons${size}`]['unknown']; + const flag = getFlag(flags, { type, size, code }); + const unknownFlag = getFlag(flags, { type, size, code: 'unknown' }); if (isMounted) { setSource(flag || unknownFlag); From fc0b6016969baa3c9f6531e0dc67746946b2e664 Mon Sep 17 00:00:00 2001 From: Alexis Puga Date: Tue, 9 Nov 2021 20:33:23 -0600 Subject: [PATCH 3/5] feat: add `from` prop Use it to pass your own flags, and made it optional. --- index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 3a79131..6061b4f 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ import React, { useState, useEffect } from 'react'; import { Image } from 'react-native'; type Props = { + from?: {}, size: 16 | 24 | 32 | 48 | 64, code: string, type?: 'flat' | 'shiny', @@ -20,7 +21,7 @@ const getFlag = (flags: {}, { type, size, code }: { return flags[type][sizeKey][code]; }; -const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { +const Flag = ({ from, size = 64, code, type = 'shiny', style }: Props) => { // @TODO Set an initial value. const [source, setSource] = useState(); @@ -29,7 +30,8 @@ const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { let isMounted = true; (async () => { - const flags = await import('./flags'); + // Use our flags or import all of them. + const flags = from || await import('./flags'); const flag = getFlag(flags, { type, size, code }); const unknownFlag = getFlag(flags, { type, size, code: 'unknown' }); @@ -43,7 +45,7 @@ const Flag = ({ size = 64, code, type = 'shiny', style }: Props) => { // @TODO Abort import instead. isMounted = false; }; - }, [type, size, code, setSource]); + }, [from, type, size, code, setSource]); return ( Date: Tue, 9 Nov 2021 21:34:14 -0600 Subject: [PATCH 4/5] feat: allow flags from ./flags' sub-directories Allow using flags from ./flags, ./flags/flat, ./flags/flat/16, etc., or directories that match that structure. --- index.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 6061b4f..6a5d1df 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,23 @@ type Props = { style?: any, }; +/** + * Find a flag exported from ./flags' sub-directories + * (or directories that match the same structure) + * and return it. + * + * @example + * import * as flags from './flags'; + * import * as flatFlags from './flags/flat'; + * import * as flatFlags16 from './flags/flat/16'; + * + * const emptyFlags = {}; + * const props = { type: 'flat', size: 16, code: 'ZW' }; + * + * getFlag(flatFlags16, props) === getFlag(flatFlags, props); // > true + * getFlag(flatFlags, props) === getFlag(flags, props); // > true + * getFlag(emptyFlags, props); // > null + */ const getFlag = (flags: {}, { type, size, code }: { type: string, size: number, @@ -18,7 +35,14 @@ const getFlag = (flags: {}, { type, size, code }: { }) => { const sizeKey = `icons${size}`; - return flags[type][sizeKey][code]; + return (type in flags // ./flags was imported. + ? flags[type][sizeKey][code] + : sizeKey in flags // ./flags/{type} was imported. + ? flags[sizeKey][code] + : code in flags // ./flags/{type}/{size} was imported. + ? flags[code] + : null + ); }; const Flag = ({ from, size = 64, code, type = 'shiny', style }: Props) => { From 15007d90d5eefd7b0d90b79f94337cdd1a9158c0 Mon Sep 17 00:00:00 2001 From: Alexis Puga Date: Tue, 9 Nov 2021 21:42:08 -0600 Subject: [PATCH 5/5] feat: document `from` prop in readme Add a description and a few examples. --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/README.md b/README.md index 013bad8..90cd33b 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,60 @@ const JustAFlag = () => ``` ### Props +#### from (optional) +#### Type: `{}` +#### Default value: `await import('./flags')` (all available flags). +The flags you want to use. + +By default, [all available flags](https://github.com/frostney/react-native-flags/blob/master/flags/index.js) are bundled/imported. +However, *bundling all flags is discouraged*, because you might not need all of them. +Instead, you could import your flags beforehand and use this prop to pass your flags. + +Below are a few examples: + +Load all flat 32 flags: +```javascript +import Flag from 'react-native-flags'; +import * as allFlatFlags32 from 'react-native-flags/flags/flat/32'; + +const JustAFlag = ({ code }) => + +``` + +Load all shiny 16/24/32/48/64 flags: +```javascript +import Flag from 'react-native-flags'; +import * as allShinyFlags from 'react-native-flags/flags/shiny'; + +const JustAFlag = ({ code, size }) => + +``` + +Load all flat/shiny 16/24/32/48/64 flags. +This is the same as removing the `from` prop: +```javascript +import Flag from 'react-native-flags'; +import * as allFlags from 'react-native-flags/flags'; + +const JustAFlag = ({ code, size, type }) => + +``` + #### code #### Type: `String` The ISO code of a flag, for example "DE", "FR" or "GB"