Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React NativeでCross Platform対応を頑張る話

20e0cb05da78d2c0efdd215de213e72a?s=47 tkow
March 04, 2021

React NativeでCross Platform対応を頑張る話

RNJ20210304

20e0cb05da78d2c0efdd215de213e72a?s=128

tkow

March 04, 2021
Tweet

Transcript

  1. ULPX 3FBDU/BUJWFͰ$SPTT 1MBUGPSNΛؤுΔ࿩

  2. 1SPGJMF ίʔϙϨʔταΠτIUUQTNPDIJDPSQDPN ϑϦʔϥϯε͔Β ڞಉ૑ۀऀͱͱ΋ʹ ๏ਓ੒Γͨ͠ձࣾͰ 
 $50΍͍ͬͯ·͢ डୗ։ൃΛ΍Γͳ͕Β 
 3/Ͱࣗࣾ։ൃΛͯ͠·͢

    
 ಉ໊ͷձ͕ࣾ͋ΔͷͰ 
 ؒҧ͍ʹؾΛ͚͍ͭͯͩ͘͞ 4&0ͷऑ͍ํͷ.0$)*Ͱ͢ 

  3. $SPTT1MBUGPSNରԠͷϞνϕʔγϣϯ ࣗࣾ։ൃͰ࡞͍ͬͯΔΞϓϦέʔγϣϯΛٸᬎϞόΠϧ"QQʹ͍ͨ͠ w ϓϩτλΠϓͰ࡞ͬͨΞϓϦΛϨεϙϯγϒରԠ͢Δʹ͋ͨͬͯͲ͏ͤϞόΠ ϧΞϓϦ΋ͭ͘ΔͳΒ3FBDU/BUJWF8FC࢖ͬͯΈ·͔͢ͱ͍͏ϊϦͰ͢ w ΋͏8FCͰ͋Δఔ౓࡞ͬͯ͠·ͬͨ͠ɺ෦෼తʹ3FBDU/BUJWF8FCίϯϙ ʔωϯτΛ࡞੒͠ஔ͖׵͑Δࣄʹ w Ͳ͏ͤͳΒࠓޙ΋༷ʑͳγʔϯͰ࢖͑Δ͍͚ͯΔίϯϙʔωϯτϥΠϒϥϦΛ

    ࡞Ζ͏ͱ͍͏͜ͱͰNPOPSFQPʹQBDLBHFΛੜ΍ͯ͠Έͨ
  4. 3FBDU/BUJWF8FC w 3FBDU/BUJWF͕FYQPSU͍ͯ͠ΔϞδϡʔϧ಺ͷ࣮૷ͷΠϯλʔϑΣʔεʹ฿ ͬͯಉ͡ه๏Ͱ8&#Ͱ࢖͑ΔίϯϙʔωϯτΛ࣮૷ͨ͠ϥΠϒϥϦ w ͜ΕʹΑͬͯιʔείʔυ্ͷ*NQPSUdGSPNbSFBDUOBUJWF`ΛίϯύΠϧ࣌ ʹSFBDUOBUJWFXFCʹࠩ͠ସ͑Δͱ͍͏࢓૊ΈͰ/BUJWF$PNQPOFOUͰ͸ͳ ͘3FBDU/BUJWF8FC$PNQPOFOUʹεΠονͰ͖ΔʢCBCFM XFCQBDLͳͲ ͷBMJBTΛ༻͍Δʣ

    w ࣮૷͸શͯXFCͷ"1*ͷൣғͰ࣮૷͞Ε͍ͯΔͷͰSFBDUOBUJWFύοέʔδ͸ ඞཁͳ͍
  5. 3FBDU/BUJWF8FC w ύοέʔδͱͯ͠ίϯϙʔωϯτΛCVJMEͯ͠࢖͏ 
 ɹCBCFM౳ͰUSBOTQJMFͯ͠ϥΠϒϥϦԽ͢ΔPSUSBOTQJMFʹ 
 ɹύοέʔδ಺ͷίʔυΛ഑ஔͯ͠ר͖ࠐΉ w ࠷ॳ͔Β3FBDU/BUJWFͱซ༻͢Δ 


    ɹOQYDSFBUFSFBDUOBUJWFXFCBQQ"QQ/BNF ηοςΟϯά̎ύλʔϯ
  6. 3FBDU/BUJWF8FC w ύοέʔδͱͯ͠ίϯϙʔωϯτΛCVJMEͯ͠࢖͏ 
 ɹCBCFM౳ͰUSBOTQJMFͯ͠ϥΠϒϥϦԽ͢ΔPSUSBOTQJMFʹ 
 ɹύοέʔδ಺ͷίʔυΛ഑ஔͯ͠ר͖ࠐΉ w ࠷ॳ͔Β3FBDU/BUJWFͱซ༻͢Δ 


    ɹOQYDSFBUFSFBDUOBUJWFXFCBQQ"QQ/BNF ηοςΟϯά̎ύλʔϯ ͬͪ͜ͷ࿩Λ͠·͢
  7. 1SPKFDUߏ੒ ᵓᴷᴷ3&"%.&NE ᵓᴷᴷMFSOBKTPO ᵓᴷᴷQBDLBHFKTPO ᵓᴷᴷQBDLBHFT ᴹᵓᴷᴷBENJODMJ ᴹᵓᴷᴷBENJOVUJMT ᴹᵓᴷᴷCBDLFOE ᴹᵓᴷᴷDPSF ᴹᵓᴷᴷNPCJMF

    ᴹᵓᴷᴷDSPTTQMBUGPSN ᴹᵋᴷᴷXFC ᵓᴷᴷUTDPO fi HKTPO ᵓᴷᴷZBSOFSSPSMPH ᵋᴷᴷZBSOMPDL MFSOBʹΑΔ.POP3FQPߏ੒ ͜͜ʹ$SPTT1MBUGPSN༻ͷϩδοΫͱ ίϯϙʔωϯτΛߏ੒͢Δ͜ͱʹ
  8. 5ZQFTDSJQUରԠ w !UZQFTSFBDUOBUJWFΛJOTUBMM͢Ε͹BMJBT͕ઃఆ͞Ε͍ͯͯ΋!UZQFT SFBDUOBUJWFͷܕఆٛΛಡΜͰ͘ΕΔͷͰ͜ΕΛར༻͢Δ w SFBDUOBUJWFXFCʹ͸ܕఆ͕ٛͳ͍ͷͰɺQMBUGPSN෼ذͰSFBDUOBUJWF XFCΛ௚઀ݺͼग़͍ͨ͠৔߹͸ɺQBDLBHFKTPOͷEFW%FQFOEFODJFTʹ 
 \ 


    !UZQFTSFBDUOBUJWFXFCOQN!UZQFTSFBDUOBUJWF 
 ^ 
 ͱهड़͢ΔͱSFBDUOBUJWFͷܕఆٛΛSFBDUOBUJWFXFCͷܕͱͯ͠ಡΜͰ͘ ΕΔͷͰඞཁͳ৔߹͸ઃఆ͢Δ
  9. 5ZQFTDSJQUରԠ "paths": { "~": ["./"], "~/*": ["./*", "./*.native", "./*.ios", "./*.android"],

    ɹ } w ΤσΟλʹղੳͤ͞ΔͨΊɺϓϥοτϑΥʔϜ͝ͱʹಡ·ͤΔ֦ுࢠΛࢦఆ͢Δɻ 
 ʢUZQFTDSJQUʹ͸XFCQBDLͷΑ͏ͳSFTPMWFFYUFOTJPOɾNPEVMFNFSHFͷΑ͏ ͳػೳ͕ͳ͘ɺQBUITͰࢦఆͨ͠NPEVMFύεҎ֎ͰSFTPMWFFYUFOTJPO͕Ͱ͖ͳ ͍૬ରύεͰ͸FYUFOTJPOΛলུͯ͠NPEVMFϚʔδ͢Δࣄ͕Ͱ͖ͳ͍ʣ w ͜ͷΑ͏ͳ෼ذΛ࣋ͭϥΠϒϥϦΛ࡞Ζ͏ͱ͢Δ৔߹ɺBMJBT fi MFQMBUGPSNKTͷ֊૚Ͱ SFRVJSF BMJBTQBUI ͷܗͰు͖ग़͞ΕΔͨΊXFCQBDL΍NFUSPͳͲCVOEMFS͕ඞཁʹͳΔ
  10. TUZMFEDPNQPOFOUT TUZMFEDPNQPOFOUTΛ࠾༻ͨ͠ ϝϦοτ w TUZMFEDPNQPOFOUT͸8FCͱ/BUJWFͰผʑͷ5IFNF1SPWJEFSΛ౉ͤΔͷͰɺ 
 UIFNFͷUIFNFQSPQFSUZͷ݁߹Λߟ͑Δඞཁ͕ͳ͍ w 8FCଆͰ΋࠾༻͍ͯ͠Ε͹ɺίϯϙʔωϯτΛҠ২͠΍͍͢ σϝϦοτ

    w 4UZMF4IFFUΛ࢖͏ΑΓ΋ύϑΥʔϚϯε͕ͪΐͬͱѱ͘ͳΔ w ΞχϝʔγϣϯͷTUBUFΛѻ͏ͱύϑΥʔϚϯε͕མͪΔ 
 3/8FCͰ͸"OJNBUFE7JFX͸DTTͱผ؅ཧʹͳΔͷͰӨڹ͸গͳ͍  w ࠷৽ͷ3FBDU/BUJWFͷίϯϙʔωϯτͷ௥ै͸ϥΠϒϥϦ͕ߋ৽͞Ε͍ͯͳ͍ 
 ͜ͱ͕͋ΓखಈͰઃఆ͢Δඞཁ͕͋Δ͕࣌͋Δ TUZMFE $PNQPOFOU ͰରԠՄೳ 
 ͳ΋ͷ΋͋Δ͕ɺͷ1SFTTBCMFͷTUZMFGVODUJPOQSPQʹରԠ͍ͯ͠ͳ͍ͳͲ 
 ͰύονΛೖΕΔඞཁ͕͋ͬͨ 

  11. #BCFMͷઃఆ ύοέʔδଆ w /BUJWFͷґଘੑอͭͨΊʹ͸3FBDU/BUJWFͷίϯϙʔωϯτʹ ͸NFUSPSFBDUOBUJWFCBCFMQSFTFU͔CBCFMQSFTFUFYQPΛར ༻ͯ͠CVJME͢Δ 
 ͨͩ͠ɺFYQPQSFTFU͸DMBTT/BNFΛॻ͖׵͑Δઃఆ͕͋ΔΒ ͘͠ɺTUZMFEDPNQPOFOUTͷTTSઃఆͱڝ߹͢ΔͬΆ͘ "OJNBUFE7JFXʹTUZMF͕͔ͭͳ͘ͳΔόά͕͋ΔΑ͏ͳͷͰ

    
 NFUSPSFBDUOBUJWFCBCFMQSFTFUΛ࠾༻
  12. #BCFMͷઃఆ ύοέʔδଆ module.exports = { presets: ['module:metro-react-native-babel-preset'], plugins: [ [

    'styled-components', { ssr: true, displayName: true, preprocess: false } ], ], env: { test: { plugins: ['styled-jsx/babel-test'], }, }, }
  13. XFCQBDLͷઃఆ ར༻ଆ config.resolve.alias = { 'react-native$': require.resolve('react-native-web'), } w 8&#༻ʹBQQMJDBUJPOΛCVJME͢Δͱ͖͸ɺSFBDUOBUJWFύοέʔδͷJNQPSUΛ

    
 SFBDUOBUJWFXFCύοέʔδʹஔ͖׵͑ΔΑ͏ʹ͢Δ
  14. XFCQBDLͷઃఆ ར༻ଆ w ͞ΒʹUSFFTIBLJOHͷԸܙΛड͚ΔͨΊʹNPOPSFQPͷΑ͏ʹUSBOTQJMFલͷ 
 ίʔυΛ௚઀ಡΈ͍ͨ৔߹͸XFCQBDLͷCVJMEUBSHFUʹϑΝΠϧΛొ࿥͢Δ 
 ඞཁ͕͋ΔɻʢಛʹTUZMFEDPNQPOFOUTOBUJWFͷΑ͏ʹ಺෦ʹSFBDUOBUJWF 
 ͷJNQPSU͕ଘࡏ͍ͯ͠ΔͷͰɺOPEF@NPEVMFT಺ʹ͋ͬͯ΋CVJME࣌ʹ͜ΕΛ

    
 SFBDUOBUJWFXFCʹࠩ͠ସ͑ͳ͍ͱΤϥʔʹͳΔʣ
  15. XFCQBDLͷઃఆ ར༻ଆ w ࠓճ͸/FYUKTΞϓϦʹίϯϙʔωϯτΛҠ২͢Δํ๏Λࢼͨ͠ͷͰ 
 OFYUUSBOTQJMFNPEVMFTΛ༻͍ͯɺ෦OPEF@NPEVMFTͷதͰ΋USBOTQJMF 
 ର৅ʹؚΊΔύοέʔδΛઃఆͨ͠ XFCQBDL͸VTFTͷઃఆͰௐ੔ const

    withTM = require('next-transpile-modules') ([ '@example_package/cross-platform’, 'styled-components/native', 'react-native-vector-icons' ]);
  16. $SPTT1MBUGPSNؒͷελΠϧௐ੔ w DTTඪ४ͷ૬ର஋ࢦఆ SFN FN ͸8FCͰ͸ධՁ͞ΕΔ͕ɺϞόΠϧଆͰ͸ 
 SFBDUOBUJWFϥΠϒϥϦ͚ͩͰ͸Ͱ͖ͳ͍ɻ 
 ʢIUUQTHJUIVCDPNWJUBMFUTSFBDUOBUJWFFYUFOEFETUZMFTIFFUͱ͍͏

    
 ϥΠϒϥϦͰSFN͕ରԠ͍ͯ͠Δ͕ɺଟػೳ͔ͭ/BUJWFͷͨΊͷ࣮૷Ͱ8FC 
 ͷ࢓༷ͱဃ཭͢Δͷ͕޷·͘͠ͳ͍ͨΊࠓճ͸ෆ࠾༻ɻ w SFN͚ͩͲ͏ʹ͔ରԠ͔ͨͬͨ͠ͷͰɺTUZMFEͷUFNQMBUFGVODUJPOʹUIFNF 
 ରԠͯ͠ຒΊࠐΉ͜ͱʹɻ XFCଆͷSFTQPOTJWFରԠ͸SFN TUZMFEͷFYUFOE 
 Ͱؤு͍ͬͯ͘
  17. $SPTT1MBUGPSNؒͷελΠϧௐ੔ SFN export type DeviceFontSizeType = | 'xxsmall' | 'xsmall'

    | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' export const DEFAULT_FONT_SIZE: Record<DeviceFontSizeType, number> = { xxsmall: 8, xsmall: 10, small: 14, medium: 16, large: 20, xlarge: 24, xxlarge: 40, } export const rem = (relativeSize: number) => { return ({ theme }: { theme: ThemeScheme }): string => `${theme.fontSize * relativeSize}px` } ࢖༻ྫ) font-size: ${rem(1)}; UFNQMBUFϦςϥϧʹຒΊࠐΉͨΊʹݱࡏͷGPOU4J[FΛ 
 ฦ͢DMPTVSFΛ࡞ΓɺSFNͷ୅ସʹͨ͠
  18. $SPTT1MBUGPSNؒͷελΠϧௐ੔ ϝσΟΞΫΤϦ w XFCଆͷڞ௨Խ͞Ε͍ͯͳ͍ίϯϙʔωϯτͷελΠϧΛ/BUJWFͱ߹Θͤ 
 ͨΓɺͦ΋ͦ΋αΠζʹΑͬͯ/BUJWFίϯϙʔωϯτΛࠩ͠ସ͍͑ͨ࣌ͷ 
 ͨΊʹϝσΟΞΫΤϦΛ࢖͏ʢແཧʹ/BUJWFίϯϙʔωϯτͱσόΠεͷج४ 
 αΠζΛ߹ΘͤΔඞཁ͸ͳ͍͕ɺ'POUTJ[F͸߹Θͤͨํ͕ແ೉ʣ

    w DSPTTQMBUGPSNଆ͸SFN͕ݻఆαΠζͰFYQPSU͞ΕΔͷͰɺ͜Ε͕Ͳ͏ͯ͠΋ 
 ࠔΔ৔߹͸TUZMFEDPNQPOFOUTOBUJWFͰFYUFOEͱTUZMFENFEJBRVFSZΛ 
 ۦ࢖ͯ͠ελΠϧΛ্ॻ͖ͯ͠ௐ੔͢Δ
  19. $SPTT1MBUGPSNؒͷελΠϧௐ੔ ϝσΟΞΫΤϦ 8&#ͷϝσΟΞΫΤϦରԠ wIUUQTHJUIVCDPN3FBDU5SBJOJOHSFBDUNFEJB wIUUQTHJUIVCDPNNPSBKBCJTUZMFENFEJBRVFSZ Λ࢖ͬͯؤுΔɻͨͩ͠ɺEFWJDFαΠζͷࢦఆͷํ๏͕ҧ͏ͷͰந৅Խͯ͠KTPONR ಉ͡ύϥϝʔλΛऔΕΔΑ͏ʹͨ͠ /BUJWFͷϝσΟΞΫΤϦରԠ const windowWidth

    = Dimensions.get('window').width; const windowHeight = Dimensions.get('window').height; Λ͔ͭͬͯɺσόΠεαΠζΛ෼ྨ͢ΔϩδοΫΛॻ͚͹0,
  20. $SPTT1MBUGPSNؒͷελΠϧௐ੔ ϝσΟΞΫΤϦ export const reactMediaQuery:ɹMediaQueryType = { xl: { maxWidth:

    1440, minWidth: 1170, },… } export const useDeviceSize = (): DeviceFontSizeType => { const matches = useMedia({ queries: reactMediaQuery }) return useMemo(() => { if (matches.lg) return 'large' if (matches.md) return 'medium' if (matches.sm) return 'small' if (matches.xsm) return 'xsmall' if (matches.xxsm) return 'xxsmall' return 'xlarge' }, [matches]) } 8&#ଆ͸ඞཁͳαΠζ·ͰͰ 
 ϝσΟΞΫΤϦΛରԠ
  21. $SPTT1MBUGPSNؒͷελΠϧௐ੔ ϝσΟΞΫΤϦ export const WebAdjustText = styled(NativeText)` white-space: pre-line; line-height:

    1.5em; ` 8&#ଆͰσόΠεαΠζ͕߹Θͳ͍৔߹΍૬ର஋ͳͲΛ࢖͍͍ͨ৔߹͸ 
 QSPQFSUZΛPWFSSJEF͢Δ
  22. 4UPSZCPPL w 3FBDU/BUJWF8FCͰ͸8FCϒϥ΢βͰදࣔͰ͖ΔͷͰɺTUPSZCPPL 
 ͷWJFXQPSUͰը໘αΠζΛ͔֬Ίͳ͕Β։ൃ͢Δͷ͕ศར w 3FBDU/BUJWFͷϙΠϯταΠζ͸04ґଘͷ6*Ͱ͸ͳ͍ݶΓઈରࢦఆʹͳΔͷͰɺ 
 7JFX1PSUͷݟͨ໨͸ը໘αΠζ͕ಉ͡Ͱ͋Ε͹ɺ8FCͰ΋ɺ.PCJMFͰ΋ಉ͡ 


    ϨΠΞ΢τʹͳΔ
  23. 4UPSZCPPL export const DarkThemeDecorator = ( story: () => React.ReactNode,

    ): ReactElement => { const colorTheme = select('colorTheme', colorThemeSelect, 'dark') const mediaSize = select('mediaSize', deviceSizeSelect, 'medium') return ( <ThemeProvider theme={{ colors: themes['colors'][colorTheme], spacers: themes['spacers'][mediaSize], fontSize: themes['fontSize'][mediaSize], }} > <View style={{ flex: 1, backgroundColor: '#222' }}>{story()}</View> </ThemeProvider> ) /BUVSBMDMBS͞ΜͷϨϙΛࢀߟʹ͠·ͨ͠IUUQTHJUIVCDPN/BUVSBMDMBSSFBDUOBUJWFTLFUDICPPLUSFFNBTUFSTSD w !TUPSZCPPLBEEPOLOPCTͰ5IFNFมߋΛ6*ͰͰ͖ΔΑ͏ʹ࢓ࠐΉ
  24. 4UPSZCPPL

  25. 3FBDU/BUJWFͰ8FCରԠͯ͠ྑ͔ͬͨ఺ w 3FBDU/BUJWF8FCࣗମ͕ϨεϙϯγϒରԠ͠΍͍͔ͭ͢ߴػೳͳ6*ϥΠϒϥ ϦͳͷͰɺίϯϙʔωϯτࣗମͷ࣮૷ָ͕ʹͳΔ΋ͷ͕͋Δ .PEBM  4OBDLCBSͳͲ  w $44Ͱॻ͚ΔͷͰҠ২͕εϜʔζʹ͍͘΋ͷ΋ଟ͍

    w Ұ౓ΧλϩάΛ࡞ͬͯ͠·͑͹8&# .PCJMFͰ࢖͍ଓ͚ΒΕΔίϯϙʔωϯ τ͕࡞ΕΔ
  26. $SPTT1MBUGPSNରԠ͕೉͍͠ͱ͜Ζ w 3FBDU/BUJWFͱίʔυϕʔεΛڞ༗͠ͳ͍৔߹ɺ/BWJHBUJPOͷڞ௨Խ͕ωοΫʹͳΔ /FYUKTͳͲ ͷ8FCϑϨʔϜϫʔΫΛ࢖͏ͱSFBDUOBWJHBUJPOͳͲ͸ར༻͢Δͷ͕೉͍͠ͷͰ 
 ผ࣮૷ͷํ͕ૣ͘ରԠՄೳ  w %FQSJDBUFEʹͳ͍ͬͯΔίϯϙʔωϯτͷରԠʢSFBDUOBUJWFXFCίϯϙʔωϯτ͕༻ҙ͞Εͯ

    ͍ͳ͍/BUJWF$PNQPOFOU"1*ΛݺͿͱΤϥʔʹͳΔɻʣҰԠ!UZQFTSFBDUOBUJWF͔Βফ͑Δ· Ͱ͸࢖͏ࣄͰରԠͨ͠ํ͕ίετ͕௿͍ɻϥΠϒϥϦ͕੾Γग़͞Ε͍ͯΔ͚ͩͰ͋Ε͹ɺBMJBTͰϥ ΠϒϥϦ໊ΛSFBDUOBUJWFXFCʹ޲͚Ε͹େৎ෉Ͱ͢ɻͦ͏Ͱͳ͚Ε͹ࣗ෼Ͱ/BUJWF 
 $PNQPOFOUͷొ࿥͕ඞཁʹͳΓ·͢ɻ w TWHͷίϯϙʔωϯτ͸8FCͰ͸࢖͍ͮΒ͍ͷͰڞ௨ԽͤͣʹSBX fi MFΛ࢖ͬͯରԠ͢Δ 
 ͷ͕Αͦ͞͏ ϞόΠϧଆͰ͸SFBDUOBUJWFTWHMPBEFS 8FCଆͰ͸TWHΛͦͷ··JNQPSU͢ΔͳͲ ͷܗʹ͢Δɻ੩తϑΝΠϧΛTUPSBHFʹอଘ͍ͨ͠৔߹͸޻෉͕ඞཁ