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

React Native for Webのこれまでから読み解くReact GUIのこれから

React Native for Webのこれまでから読み解くReact GUIのこれから

React Native Matsuri 2021で発表したスライドです。
https://reactnative-matsuri.com/ja

Yukiya Nakagawa

October 02, 2021
Tweet

More Decks by Yukiya Nakagawa

Other Decks in Programming

Transcript

  1. Who am I • Yukiya Nakagawa a.k.a Nkzn (ͳ͔͟Μ) •

    ৽ׁࡏॅ • ೋࣇͷ෕Ͱ࠺ͷ෉ʢࠓ೔΋ϫϯΦϖҭࣇ͋Γ͕ͱ͏🙏ʣ • ࢿ࢈ӡ༻͓ख఻͍αʔϏεmoneiroͷITཪํ • ٕज़ॻయͷWebϑϩϯτΤϯυˍܾࡁΞϓϦ୲౰ • React 2015ʙ / React Native 2017ʙ 2 0:38
  2. useHover import React from "react"; import { useHover } from

    "react-gui/use-hover"; export default function App() { const [hovered, onHoverChange] = React.useState(false); const ref = useHover({ onHoverChange }); return ( <div ref={ref} style={{ width: 200, height: 200, margin: "50px auto", border: "1px solid black", backgroundColor: hovered ? "orange" : null }} /> ); } • RefྖҬ΁ͷϗόʔΛݕग़ 11
  3. ͓·͚ useHoverState function useHoverState() { const [hovered, onHoverChange] = useState(false);

    const ref = useHover({ onHoverChange }); return [ref, hovered]; } ࢖͍΍͘͢ϥοϓ refͱhovered͚ͩެ։ 12
  4. ਌ͷإΑΓݟͨ React NativeͬΆ͞ export default function App() { const [ref,

    hovered] = useHoverState(); return ( <View style={styles.container}> <View ref={ref} style={[ styles.card, { backgroundColor: hovered ? "#ffa" : "#fff" } ]} > <Image source={imageUrl} style={styles.thumbImg} /> <View style={{ justifyContent: "center" }}> <Text accessibilityRole="heading" accessibilityLevel={3} style={styles.title} > @Nkzn </Text> <View style={{ height: 8 }} /> <Text style={styles.description}> Matsuri 2021 Speaker </Text> </View> </View> </View> ); } • View, Text, Image • StyleSheet.create(ޙड़)Ͱ ࡞ͬͨstylesΛࢀর • ελΠϧΛ഑ྻͰϚʔδ 15 4:26
  5. ਌ͷإΑΓݟͨ React NativeͬΆ͞ export default function App() { const [ref,

    hovered] = useHoverState(); return ( <View style={styles.container}> <View ref={ref} style={[ styles.card, { backgroundColor: hovered ? "#ffa" : "#fff" } ]} > <Image source={imageUrl} style={styles.thumbImg} /> <View style={{ justifyContent: "center" }}> <Text accessibilityRole="heading" accessibilityLevel={3} style={styles.title} > @Nkzn </Text> <View style={{ height: 8 }} /> <Text style={styles.description}> Matsuri 2021 Speaker </Text> </View> </View> </View> ); } • View, Text, Image • StyleSheet.create(ޙड़) Ͱ࡞ͬͨstylesΛࢀর • ελΠϧΛ഑ྻͰϚʔδ 16 4:45
  6. ਌ͷإΑΓݟͨ React NativeͬΆ͞ export default function App() { const [ref,

    hovered] = useHoverState(); return ( <View style={styles.container}> <View ref={ref} style={[ styles.card, { backgroundColor: hovered ? "#ffa" : "#fff" } ]} > <Image source={imageUrl} style={styles.thumbImg} /> <View style={{ justifyContent: "center" }}> <Text accessibilityRole="heading" accessibilityLevel={3} style={styles.title} > @Nkzn </Text> <View style={{ height: 8 }} /> <Text style={styles.description}> Matsuri 2021 Speaker </Text> </View> </View> </View> ); } • View, Text, Image • StyleSheet.create(ޙड़)Ͱ ࡞ͬͨstylesΛࢀর • ελΠϧΛ഑ྻͰϚʔδ 17 5:04
  7. ਌ͷإΑΓ(ུ) const styles = StyleSheet.create({ container: { padding: 24, backgroundColor:

    "#eee", height: "100vh" }, card: { boxShadow: "2px 2px 4px #ccc", padding: 16, backgroundColor: "#fff", borderRadius: 8, flexDirection: "row", maxWidth: 500, width: "100%", alignSelf: "center" }, thumbImg: { width: 100, height: 100, borderWidth: 1, borderColor: "#ccc", borderRadius: 50, marginRight: 16 }, title: { fontSize: 24, fontWeight: "700" }, description: { color: "#888" } }); ελΠϧʹ࢖͑Δϓϩύ ςΟ͸ϥϯλΠϜґଘ shadowܥ͸boxShadow ը૾Λؙ͘͢Δͷ͸ׂͱ͍ ͭ΋௨Γͷ΍Γํ 18 5:23
  8. ਌ͷإΑΓ(ུ) card: { boxShadow: "2px 2px 4px #ccc", padding: 16,

    backgroundColor: "#fff", borderRadius: 8, flexDirection: "row", maxWidth: 500, width: "100%", alignSelf: "center" }, ελΠϧʹ࢖͑Δϓϩύ ςΟ͸ϥϯλΠϜґଘ shadowܥ͸boxShadow ը૾Λؙ͘͢Δͷ͸ׂͱ͍ ͭ΋௨Γͷ΍Γํ 19 5:42
  9. ਌ͷإΑΓ(ུ) thumbImg: { width: 100, height: 100, borderWidth: 1, borderColor:

    "#ccc", borderRadius: 50, marginRight: 16 }, ελΠϧʹ࢖͑Δϓϩύ ςΟ͸ϥϯλΠϜґଘ shadowܥ͸boxShadow ը૾Λؙ͘͢Δͷ͸ׂͱ͍ ͭ΋௨Γͷ΍Γํ 20 6:01
  10. ࠓ೔ͷ͓࿩ • React GUIʹ৮ͬͯΈͨʢࠓऴΘͬͨʣ • React Native for Webͱ͸ •

    React Native for Web͸ͳͥੜ·Εͨͷ͔ • React GUIͷ͜Ε͔Β 25 7:55
  11. React GUI͸React Native for Webͷܥේ • ͲͪΒ΋࡞ऀ͸Nicolas Gallagherࢯ • React

    GUI͸Facebook໊͚ٛͩͲNPMͳͲͰࢯͷؔΘΓ͕ݟ͑Δ • https://www.npmjs.com/package/react-gui • React NativeͬΆ͍ίʔυΛϒϥ΢βͰಈ͔͢Ξϓϩʔν 32 10:08
  12. React Native for Web͓͞Β͍ᶃ • https://necolas.github.io/react-native-web/ • 2017೥9݄ʹv0.1.0͕ެ։ • 2017೥4݄ʹϦϦʔε͞ΕͨTwitter

    Lite (mobile.twitter.com) Ͱ 
 UIϥΠϒϥϦͱͯ͠࠾༻͞Εͨ • ࡞ऀͷNicolasࢯTwitter LiteϓϩδΣΫτ౰࣌ͷςοΫϦʔυ 34 10:46
  13. "OESPJE J04 8JOEPXT "OESPJE4%, J044%, 7JTVBM$ 3/"OESPJE3VOUJNF 3/J043VOUJNF 3/8JOEPXT3VOUJNF 3/"OESPJE

    /BUJWF$PNQPOFOUT"1*T 3/J04 /BUJWF$PNQPOFOUT"1*T 3/8JOEPXT /BUJWF$PNQPOFOUT"1*T 3FBDU/BUJWF+BWB4DSJQU"1* 0VS"XFTPNF"QQMJDBUJPO } } ϥϯλΠϜ (Java, Obj-C, C++) UIϥΠϒϥϦ (JavaScript) 44 13:56 $PNQPOFOU"1*ͷ /BUJWF࣮૷ +4*΍+4&OHJOF
  14. React Native for Webͷਖ਼ମ • React Native͸ϥϯλΠϜΛ࠶ݱ͠ͳ͍ • React Nativeͱಉ໊͡લɾಉ͡propsɾಉ͡ݟͨ໨ͷίϯϙʔωϯτ

    ͕ੜ͍͑ͯΔʢ಺෦࣮૷͸ͨͩͷdiv΍span΍inputʣ • React Nativeͱಉ໊͡લɾಉ͡Ҿ਺ɾಉ͡ڍಈͷAPI͕ੜ͍͑ͯΔ • ͨ·ͨ·React Nativeͱಉ͡ΠϯλʔϑΣʔεΛ͍࣋ͬͯΔ͚ͩͷɺ React Nativeͱ͸ґଘؔ܎ͷͳ͍UIϥΠϒϥϦ 46 14:34
  15. "OESPJE J04 8JOEPXT "OESPJE4%, J044%, 7JTVBM$ 3/"OESPJE3VOUJNF 3/J043VOUJNF 3/8JOEPXT3VOUJNF 3/"OESPJE

    /BUJWF$PNQPOFOUT"1*T 3/J04 /BUJWF$PNQPOFOUT"1*T 3/8JOEPXT /BUJWF$PNQPOFOUT"1*T 3FBDU/BUJWF+BWB4DSJQU"1* 0VS"XFTPNF"QQMJDBUJPO #SPXTFS %0."1*T #VJMUJO'VODUJPOT 3FBDU%0. 3FBDU/BUJWFGPS8FC $PNQPOFOUT"1*T 47 14:53
  16. ਌ͷإΑΓݟͨ React NativeͬΆ͞ export default function App() { const [ref,

    hovered] = useHoverState(); return ( <View style={styles.container}> <View ref={ref} style={[ styles.card, { backgroundColor: hovered ? "#ffa" : "#fff" } ]} > <Image source={imageUrl} style={styles.thumbImg} /> <View style={{ justifyContent: "center" }}> <Text accessibilityRole="heading" accessibilityLevel={3} style={styles.title} > @Nkzn </Text> <View style={{ height: 8 }} /> <Text style={styles.description}> Matsuri 2021 Speaker </Text> </View> </View> </View> ); } • View, Text, Image • StyleSheet.create(ޙड़)Ͱ ࡞ͬͨstylesΛࢀর • ελΠϧΛ഑ྻͰϚʔδ ͜Ε͕3FBDU%0.Ͱ΋ಡΊΔܗʹͳΔΘ͚Ͱ͢ 48
  17. React Native for Webͷਖ਼ମ • React Native͸ϥϯλΠϜΛ࠶ݱ͠ͳ͍ • React Nativeͱಉ໊͡લɾಉ͡propsɾಉ͡ݟͨ໨ͷίϯϙʔωϯτ

    ͕ੜ͍͑ͯΔʢ಺෦࣮૷͸ͨͩͷdiv΍span΍inputʣ • React Nativeͱಉ໊͡લɾಉ͡Ҿ਺ɾಉ͡ڍಈͷAPI͕ੜ͍͑ͯΔ • ͨ·ͨ·React Nativeͱಉ͡ΠϯλʔϑΣʔεΛ͍࣋ͬͯΔ͚ͩͷɺ React Nativeͱ͸ແؔ܎ͷUIϥΠϒϥϦ 2Ͳ͏΍࣮ͬͯݱ͍ͯ͠Δͷʁ 49
  18. React Native for Web͸ͨͩͷUIϥΠϒϥϦ import { Image, Text, View, StyleSheet

    } from ‘react-native-web’; XFCQBDLͷSFTPMWFBMJBT౳Ͱ ໊લΛޡຐԽͯ͠lSFBDUOBUJWFzͱͯ͠ *NQPSUͰ͖ΔΑ͏ʹ͍ͯ͠Δͷ͕&YQP8FC 51 16:09
  19. ͓΍ɺ͜Μͳͱ͜Ζʹ੔ཧ͞ΕͨGUI͕ • ೚ҙͷྖҬ಺Λ׳ੑεΫϩʔϧ͍ͨ͠ • → ScrollView • ॲཧ଴ͪͷϓϩάϨεόʔΛग़͍ͨ͠ • →

    ProgressBar, ActivityIndicator • େྔͷσʔλΛলϝϞϦͰදࣔͰ͖ΔϦετػߏ • → FlatList 61 19:19
  20. React NativeͷAPI͸Α͘Ͱ͖ͯΔʦཁग़యʧ • ͦͷདྷྺ͔ΒɺiOS SDKͱAndroid SDKͷ࠷େެ໿Λࢤ޲͍ͯ͠Δ • iOSઌߦͰ࡞ΒΕͨͷͰɺ໋໊͕iOSدΓͰ͸͋Δ • for

    Windows΍for macOS͕࣮૷͞Εͨ఺͔Β΋APIσβΠϯͷ൚༻ੑ ͕Ӑ͍஌ΕΔʢ΄Μͱ͔……ʁʣ • GUIΞϓϦέʔγϣϯ࡞Γʹదͨ͠ϑϨʔϜϫʔΫΛ࡞ΔͳΒɺAPI ͱͯ͠React NativeΛਅࣅΔͷ͸ѱ͘ͳ͍Ξϓϩʔν 62 19:38
  21. ਌ͷإΑΓݟͨ React NativeͬΆ͞ export default function App() { const [ref,

    hovered] = useHoverState(); return ( <View style={styles.container}> <View ref={ref} style={[ styles.card, { backgroundColor: hovered ? "#ffa" : "#fff" } ]} > <Image source={imageUrl} style={styles.thumbImg} /> <View style={{ justifyContent: "center" }}> <Text accessibilityRole="heading" accessibilityLevel={3} style={styles.title} > @Nkzn </Text> <View style={{ height: 8 }} /> <Text style={styles.description}> Matsuri 2021 Speaker </Text> </View> </View> </View> ); } • View, Text, Image • StyleSheet.create(ޙड़)Ͱ ࡞ͬͨstylesΛࢀর • ελΠϧΛ഑ྻͰϚʔδ Ͱɺ͜͏ͳͬͨΘ͚ 64
  22. React Native for WebͷϞνϕʔγϣϯ • React DOMͷੈքʹ΋શ෦ೖΓGUIπʔϧΩοτ͕ཉ͍͠ • ෳ਺ϓϥοτϑΥʔϜͷதͰୟ্͖͛ΒΕͨɺReact NativeͷதཱతͳAPIσβΠϯ

    Λϒϥ΢βʹ΋औΓࠐΜͰΈΑ͏ • CSSͷࠇຐज़Λ֮͑ͳͯ͘΋ҰൠతͳGUIΞϓϦέʔγϣϯΛ૊ΊΔΑ͏ʹͳΔͧʂ • ͦΕͰ͍ͯσβΠϯ্ͷΦϐχΦϯ͸ͳ͍ͷͰɺ޷͖ͳσβΠϯͷUIϥΠϒϥϦΛඃ ͤΒΕΔͧʂʢReact Native Paperͱ͔NativeBaseͱ͔࢖͑Δʣ • WAI-ARIA࢓༷ͷAccessibilityରԠ͕΍Γ΍͍͢Α͏ʹ഑ྀ͢Δ $IBLSB6*ͱͷҧ͍ 65 20:35
  23. ୤ग़ϋονͷ ࡞Γ΍͢͞ import React, { useCallback } from 'react'; import

    { View } from 'react-native'; import { useDropzone } from 'react-dropzone'; export type Props = { onFileSelected: (file: File) => void; }; export const UploadProductDlc: React.FC<Props> = ({ onFileSelected }) => { const onDrop = useCallback( (acceptedFiles) => { if (!acceptedFiles || acceptedFiles.length === 0) return; onFileSelected(acceptedFiles[0]); }, [onFileSelected] ); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accept: [ 'application/pdf' ], }); return ( <View> <div {...getRootProps()} style={{ backgroundColor: isDragActive ? 'lightgray' : ‘gray' }} > <input {...getInputProps()} /> <p>ϑΝΠϧΛ௥Ճ͢Δ (࠷େ500MB·Ͱʣ</p> </div> </View> ); }; React Nativeͷख๏Ͱղܾ͢Δͷ ͕໘౗ʹͳͬͨΒɺϒϥ΢βͷख ๏ʹಀ͛ͯ΋͍͍ ීஈͱҧͬͯϒϦοδ͕͍Βͳ͍ ࣮ՈͷΑ͏ͳ҆৺ײ ϒϥ΢β޲͚ϥΠϒϥϦ 7JFXͷதʹEJWΛஔ͍ͯ΋͍͍ UploadProductDlc.web.tsx 68 21:32