Slide 1

Slide 1 text

React HooksͰ Λ৐Γ͜ͳ͢ 2019-11-2 ϑϩϯτΤϯυΧϯϑΝϨϯε2019 Yahoo! JAPAN / GYAO!

Slide 2

Slide 2 text

MASANARI HAMADA ͳΓΖ͏ @narirow ͓࢓ࣄ Yahoo! JAPAN 2015೥৽ଔೖࣾ GYAO! WebͷϑϩϯτΤϯυΞʔΩςΫνϟ࡮৽ GYAO! ಈըϓϨʔϠʔ࡮৽ GYAO! iOS SwiftԽ / ϦϑΝΫλϦϯά౳ σβΠϯγεςϜ / JAMStack / WEBඪ४ ౳ʹڵຯ͕͋Γ·͢ ࣥච WEB+DB PRESS ͷϑϩϯτΤϯυ࿈ࡌهࣄͱͯ͠Storybookɺ HeadlessCMSͷهࣄΛࣥච

Slide 3

Slide 3 text

APENDIX ಈըϓϨʔϠʔʁ ಛ௃ͱෳࡶੑʹ͍ͭͯ Videoͷෳࡶͳঢ়ଶͷ੍ޚΛReactHooksΛ༻͍ͯߦ͏ ReactHooksͰϓϨʔϠʔͷUIΛ࡞Γ͜Ή

Slide 4

Slide 4 text

օ͞Μ͸ WEB Ͱ ಈը Λ؍Δ ػձ͸͋Γ·͔͢ʁ ੈͷதʹ͸ͨ͘͞ΜͷVODαʔϏε͕͋Γ·͢

Slide 5

Slide 5 text

ಈըϓϨʔϠʔͷੈք΁ ಈըίϯςϯπͷັྗΛ࠷େݶҾ͖ग़ͨ͢Ίʹ͸ɺ շదʹ࠶ੜ͠շదʹૢ࡞͕Ͱ͖ΔϓϨʔϠʔ͕ෆՄܽ

Slide 6

Slide 6 text

ϓϨʔϠʔͷ಺෦ͰԿ͕ى͖͍ͯΔ͔ɺͦͷ՝୊Λ஌Ζ͏ ಈըϓϨʔϠʔͷੈք΁

Slide 7

Slide 7 text

1. ಈըϓϨʔϠʔͷෳࡶੑ

Slide 8

Slide 8 text

WEB͸Ͳ͏΍ͬͯಈըΛ࠶ੜ͢Δʁ HTMLVideoElement HTMLVideoElement͸ɺHTMLMediaElementΛܧঝͨ͠WEBͰಈը ϑΝΠϧΛऔΓѻ͏ͨΊͷHTMLཁૉɻ ಈըʹؔ͢ΔΠϯλϥΫςΟϒͳॲཧΛߦ͏͜ͱ͕Ͱ͖·͢ɻ

Slide 9

Slide 9 text

͋ͳͨͷϒϥ΢β͸ಈը࠶ੜͰ͖·ͤΜ ୯७ͳ࠶ੜ͸ͨͬͨ͜Ε͚ͩɻϒϥ΢β͸ݡͯ͘ɺΦϓγϣϯͷtype ଐੑ͔ΒϑΝΠϧΛμ΢ϯϩʔυͯ͠࠶ੜ͢Δ͔Λ൑அ͠·͢ɻ ଐੑʹΑͬͯॳظ஋΍ಈ࡞ΛࢦఆͰ͖ɺΠϯλʔϑΣʔε͔ΒԻྔɺ όοϑΝϦϯάɺ࠶ੜҐஔͳͲΛ੍ޚͰ͖·͢ɻ

Slide 10

Slide 10 text

ඪ४ͷ PlayerUI ͸ɺ֤ϒϥ΢βͰσβΠϯ΍ػೳʹ͕ࠩ͋Γ·͢ɻ Safari Google Chrome Ͱɺ֤ϒϥ΢βͷඪ४ίϯτϩʔϧUIදࣔ Ͱ͖·͢ɻ

Slide 11

Slide 11 text

ͦͷͨΊɺҰൠతʹϓϨʔϠʔΛ࡞੒͢Δʹ͸ɺ ೚ҙͷUIΛ্͔Β෴͍ඃͤͯػೳΛ௥Ճ͠ɺΫϩεϒϥ΢βͰಈ࡞ ͢Δݻ༗ͷϓϨʔϠʔΛ࡞੒͍ͯ͘͜͠ͱʹͳΓ·͢ɻ ΧελϜUI

Slide 12

Slide 12 text

࠶ੜʹؔ܎͢Δٕज़ ετϦʔϛϯά࠶ੜ MediaSourceExtension HLS (HTTP Live Streaming) MPEG-DASH ίϯςϯπอޢ Encrypted Media Extensions DRMϥΠηϯε ࣈນ WEB VTT ಈը޿ࠂ VAST / VMAP (IAB) ࠶ੜʹؔ࿈͢Δٕज़͸ɺ௿ϨΠϠʔΛؚΈɺଟ༷ͳ෼໺ʹΘͨΓ·͢ɻ

Slide 13

Slide 13 text

࠶ੜͷΠϕϯτ (HTML Media Events) ❖ loadedmetadata…. ❖ loadeddata……….. ❖ canplay……………. ❖ canplaythrough….. ❖ waiting……………. ❖ etc…. ಈըͷϝλσʔλ͕ಡΈࠐ·Εͨ࣌ ಈըͷॳظϑϨʔϜ͕ಡΈࠐ·Εͨ࣌ ࠶ੜ͕Մೳͱͳͬͨ࣌ όοϑΝϦϯάΛߟྀͯ͠࠶ੜ͕Մೳͱͳͬͨ࣌ ࠶ੜʹඞཁͳσʔλ͕ෆ଍͠࠶ੜ͕ఀࢭͨ࣌͠ ͜ΕΒͷٕज़Λ΋ͬͯ಺෦ͰߦΘΕͨॲཧ͸ɺө૾࠶ੜʹؔ͢ΔΠϕ ϯτͱͯ͠ɺදࣔॲཧܥʹ௨஌͞Ε·͢ɻ

Slide 14

Slide 14 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Ϣʔβʔૢ࡞ Video Element Player UI ө૾ͷঢ়ଶΛ൓ө ಈըͷঢ়ଶͷ͔ͨ·Γ ෳࡶͳUIૢ࡞

Slide 15

Slide 15 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Ϣʔβʔૢ࡞ͷঢ়ଶ Video Element Player UI ө૾ͷঢ়ଶΛ൓ө ϓϨʔϠʔ͸ʮঢ়ଶʯͱ ෳࡶͳʮϢʔβʔૢ࡞ʯͷަࠩ఺

Slide 16

Slide 16 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Ϣʔβʔૢ࡞ͷঢ়ଶ Video Element Player UI ө૾ͷঢ়ଶΛ൓ө REACT

Slide 17

Slide 17 text

͜ͷෳࡶੑΛREACTʹͲ͏ ൓ө͍͔ͯ͘͠

Slide 18

Slide 18 text

11/1 GYAO!ετΞ ϦχϡʔΞϧ https://gyao.yahoo.co.jp/store

Slide 19

Slide 19 text

ͦͷࡍʹɺϓϨʔϠʔΛ ReactHooksΛ࢖༻ͨ͠ΞʔΩςΫνϟͰ࣮૷ɻ ❖ preact 10.0 (hooks) ❖ dash.js with DRM

Slide 20

Slide 20 text

2. ͷঢ়ଶ؅ཧ

Slide 21

Slide 21 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Ϣʔβʔૢ࡞ͷঢ়ଶ ө૾ͷঢ়ଶΛ൓ө લड़ͨ͠Α͏ʹɺϓϨʔϠʔʹ͸ओʹɺө૾ͷঢ়ଶมԽͱɺϢʔβʔ ૢ࡞ʹؔ͢Δঢ়ଶมԽͷओʹ2ͭΛ੍ޚ͠·͢ɻ Player UI Video Element ಈըͷঢ়ଶͷ͔ͨ·Γ ෳࡶͳUIૢ࡞

Slide 22

Slide 22 text

❌ ͜Ε·Ͱͷෛ࠴ ҎલͷPlayerͰ͸ɺ֤ཁૉͷίϯϙʔωϯτ͝ͱʹΠϕϯτΛϋϯυ ϧ͠ɺݸผʹ੾Γସ͑Δ͜ͱΛߦ͍ͬͯ·ͨ͠ɻ ө૾ঢ়ଶ (currentTime) timeupdateΠϕϯτ Player UI Video Element γʔΫόʔ

Slide 23

Slide 23 text

͜ͷख๏͸ཁྖ͕ѱ͘ɺεέʔϧ͠·ͤΜͰͨ͠ɻ ෼ׂ͸Ͱ͖͍ͯΔ΋ͷͷɺvideoͷΠϕϯτۦಈͷঢ়ଶมԽΛݸผʹه ड़͓ͯ͠Γɺඞཁͳॲཧ͕ࢄΒ͹ͬͯɺຊདྷͷίϯϙʔωϯτ͕ߦ͍ ͍ͨಈ࡞Λ௥͏͜ͱ͕ࠔ೉ͱͳͬͨͷͰ͢ɻ Video Element ❌

Slide 24

Slide 24 text

React Hooks

Slide 25

Slide 25 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Video Element ঢ়ଶ (STORE) มߋ௨஌ (ACTION) Player UI ࠓճ͸ɺReactͰө૾(video)ͷঢ়ଶΛద੾ʹѻ͏ͨΊʹɺVideo ElementΛঢ়ଶͱΞΫγϣϯʹ෼཭͠ɺͦͷ৘ใͷΈࢀর͢ΔΑ͏ʹม ߋ͠·ͨ͠ɻ

Slide 26

Slide 26 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Video Element ঢ়ଶ (STORE) มߋ௨஌ (ACTION) Player UI ͜ͷ࣌ɺSTORE(useContext)ͱͯ͠ѻ͏ঢ়ଶʹ͸ɺUIʹඞཁ ࠷খݶͳ஋ʹߜΓ·͢ɻ

Slide 27

Slide 27 text

ෳ਺ͷΠϕϯτΛ߹੒ͯ͠࠷ऴతʹҰͭͷ஋Λར༻͢Δ৔߹ɺͦͷ໾ׂ ಺Ͱ͋Ε͹ɺ͜ͷதͰٵऩ͠·͢ɻ ReactHooksͰߦ͏৔߹ɺҎԼͷΑ͏ʹͳΓ·͢ɻ ࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Video Element ঢ়ଶ (STORE) มߋ௨஌ (ACTION) Player UI

Slide 28

Slide 28 text

// ࠶ੜऴྃ useEffect(() => { const onEnded = () => { setEnded(true); }; player.on('ended', onEnded); return () => { player.off('ended', onEnded); }; }, [player]); // ϦϓϨΠ useEffect(() => { if (!ended) return () => {}; const onReplay = () => { setSessionId(generateSessionId()); setEnded(false); player.off('playing', onReplay); }; player.on('playing', onReplay); return () => { player.off('playing', onReplay); }; }, [ended, player]);

Slide 29

Slide 29 text

3. ContextͱύϑΥʔϚϯε

Slide 30

Slide 30 text

࠶ੜٕज़ ө૾ঢ়ଶ ෳ਺ͷ࠶ੜΠϕϯτ Video Element ঢ়ଶ (STORE) มߋ௨஌ (ACTION) Player UI ࠶ϨϯμϦϯά ࠶ϨϯμϦϯά ࠶ϨϯμϦϯά ❌ Context͸ศརͰ͕͢ɺ͢΂ͯͷ৘ใΛ΋ͨͤͯ͠·͏ͱɺ ߋ৽ස౓ͷߴ͍ঢ়ଶʹҾ͖ͮΒΕɺProvidor഑ԼͷίϯϙʔωϯτͰ࠶ ϨϯμϦϯά͕ൃੜ͠·͢ɻ

Slide 31

Slide 31 text

interface InitialState = { currentTime: number //- ݱࡏͷ࠶ੜҐஔ(࣌ؒ) media: Media //- ө૾ͷϝλ৘ใ } ݱࡏͷ࣌ؒ͸ө૾͕࠶ੜ͞ΕΔͨͼʹසൟͳߋ৽͕૸Γ·͕͢ɺ ө૾ͷϝλσʔλ͸ॳճͷΈσʔλΛऔಘͯ͠ɺ࠶ಡΈࠐΈ͕૸ Βͳ͍ݶΓ͸มԽ͠ͳ͍஋Ͱ͢ɻ ྫ͑͹ɺҎԼͷΑ͏ͳঢ়ଶΛ΋͍ͬͯͨ৔߹

Slide 32

Slide 32 text

1: ContextΛػೳυϝΠϯ͝ͱʹ෼ׂ͢Δ ߋ৽ස౓΍໨తͷҟͳΔঢ়ଶΛɺಉ͡Contextʹ͸ೖΕͳ͍Α͏ʹ͠ ·͢ɻ ϓϨʔϠʔͷContextΛߋ৽ස౓ͱར༻༻్͝ͱʹΘ͚ɺޓ͍ʹӨڹ ͠ͳ͍Α͏ʹ͢Δ͜ͱ͕ॏཁͰ͢ɻ

Slide 33

Slide 33 text

ঢ়ଶ (STORE) MediaContext (ө૾ϝλ) media diration PlaybackContext (ө૾ͷ࠶ੜ৘ใ) currentTime, paused, ended, seeking, waiting, buffer PlaybackSettingContext (ө૾ͷ࠶ੜ৘ใ) muted, playbackRate, videoQuality, isFullscreen ߋ৽ස౓ ߴ ߋ৽ස౓ ௿ ෼ղ

Slide 34

Slide 34 text

MediaContext (ө૾ϝλ) PlaybackContext (ө૾ͷ࠶ੜ৘ใ) PlaybackSettingContext (ө૾ͷ࠶ੜ৘ใ) ߋ৽ස౓ ߴ ߋ৽ස౓ ௿ ස౓ͱ໾ׂ͝ͱʹ෼ׂͨ͜͠ͱʹΑΓɺ ContextʹΑΔ࠶ϨϯμϦϯάίετΛ཈͑Δɻ γʔΫόʔɺ࣌ؒදࣔɺόοϑΝදࣔ λΠτϧදࣔɺαϜωΠϧ ઃఆ

Slide 35

Slide 35 text

2: useMemoΛڬΉ ෛՙͷߴ͍ίϯϙʔωϯτʹͷΈඞཁͳ৘ใΛ౉͠ϝϞԽ͠·͢ɻ ਌ͷϨϯμϦϯά͸࣮ߦ͞Ε·͕͢ɺuseMemoͷೖྗ͕ಉ͡৔߹ ʹɺࢠίϯϙʔωϯτ͸ϨϯμϦϯά͞Εͳ͘ͳΓ·͢ɻ function MediaDitails () { const { media } = useContext(PlayerContext); return } const MediaInfomation = useMemo(media => { // ԼهʹϨϯμϦϯάίετͷߴ͍ॲཧΛهड़ return ; }, [media]);

Slide 36

Slide 36 text

4. ϫʔΫΞϥ΢ϯυͷ੍ޚ

Slide 37

Slide 37 text

σόΠε΍ϒϥ΢βʹࠩҟ͕ൃੜ͢Δॲཧ͸ɺঢ়ଶΛ࡞Γग़͢ ࣌΍ɺந৅Խͨ͠ϨΠϠʔΛڬΉ͜ͱͰٵऩ͠ɺ֎ଆͷUI෦෼ Ͱҙࣝ͠ͳ͍ߏ଄Λͭ͘Γ·͢ɻ UIଆ͕ʮ༨ܭͳ͜ͱʯΛҙࣝ͠ͳ͍Α͏ʹ Playerͷ಺෦Ͱ͸͜͏ͨ͠ॲཧ͕ଟ͘ൃੜ͢ΔͨΊ ౎౓ରԠ͢Δͱഁ୼͢Δ

Slide 38

Slide 38 text

D document.addEventListener('fullscreenchange', handler); document.addEventListener('webkitfullscreenchange', handler); document.addEventListener('mozfullscreenchange', handler); document.addEventListener('MSFullscreenChange', handler); UIଆ͕ʮ༨ܭͳ͜ͱʯΛҙࣝ͠ͳ͍Α͏ʹ ྫ͑͹fullscreenΛߦ͏ॲཧͷ৔߹… શ෦ҧ͏! import { requestVideoFullscreen, exitVideoFullscreen } from './util/video-fullscreen';

Slide 39

Slide 39 text

ྫ͑͹ɺGoogle͕࡞੒͢ΔShakaPlayerͰ͸ɺଟ͘ͷॲཧΛಠࣗ ͷPollyfillΛ௨͢͜ͱͰந৅Խ͠ɺར༻ଆͰ͸ͦͷࠩΛҙࣝ͠ͳ͍ Α͏ʹهड़͍ͯ͠·͢ɻࢲୡ΋͜ͷ࣮૷Λࢀߟʹ͠·ͨ͠ɻ https://github.com/google/shaka-player/tree/master/lib/polyfill (ྫ) EMEͷMediaKeysΛऔಘ͢Δॲཧ

Slide 40

Slide 40 text

5. ϓϨʔϠʔͷʮࣗવͳಈ࡞ʯΛ࡞Δ

Slide 41

Slide 41 text

ྫ͑͹ɺϓϨʔϠʔʹ͸ίϯτϩʔϧόʔ͕දࣔ͞Ε·͢ ͕ɺਓ͕ؒࣗવͱײ͡Δදࣔͷಈ͖Λ࡞ΔͨΊʹ͸ɺ࣍ͷΑ ͏ͳ੍ޚ͕ඞཁͰ͢ɻ ίϯτϩʔϧόʔ

Slide 42

Slide 42 text

❖ Ϣʔβʔ͕Կ͔ૢ࡞͍ͯ͠Δ࣌͸දࣔ͢Δ ❖ Ϣʔβʔ͕ૢ࡞Λऴྃͨ͠ͱ͖ʹ͸ফ͑Δ ❖ ॳճ͸਺ඵදࣔ͢Δ (ॳճʹද͓͔ࣔͯ͠ͳ͍ͱͲΜͳૢ࡞͕Ͱ͖Δ͔ೝࣝͰ͖ͳ͍ͨΊ) ❖ ಈը͕ఀࢭͨ͠ͱ͖͸දࣔ͢Δ (Ұ࣌ఀࢭ͍ͯ͠Δ͜ͱΛ఻͑ΔͨΊ) ୯७ͳϗόʔͷΈͰ͸ɺࣗવͳಈ࡞ʹͳΒͳ͍

Slide 43

Slide 43 text

࣮ࡍʹಈ࡞ΛݟͯΈΔ

Slide 44

Slide 44 text

❖ Ϣʔβʔ͕Կ͔ૢ࡞͍ͯ͠Δ࣌͸දࣔ͢Δ

Slide 45

Slide 45 text

❖ ૢ࡞͕ऴྃͯ͠ɺಈըʹूத࢝͠ΊͨΒফ͑Δ

Slide 46

Slide 46 text

❖ Ϛ΢ε͕ը໘಺֎ʹདྷͨͱ͖͸ଈ࠲ʹදࣔɾඇදࣔ

Slide 47

Slide 47 text

❖ ॳճ͸͠͹Β͘ද͓ࣔͯ͘͠

Slide 48

Slide 48 text

ঢ়ଶͷ߹੒ΛReactͰͲͷΑ͏ʹѻ͏͔ 1ͭͷؔ৺͝ͱʹΧελϜϑοΫΛ࢖༻ͯ͠෼཭͢Δ ྫ͑͹্هͷΑ͏ͳɺ ❖ ॳճද͍ࣔͯ͠Δ͔ ❖ Ϣʔβʔ͕ཁૉʹؔ৺Λ΋͍ͬͯΔ͔ Λ1୯Ґͱͯ͠ΧελϜϑοΫΛ࡞੒͠·͢ɻ

Slide 49

Slide 49 text

export const useUserAttention = attentionDistractedIntervalMillis => { // - ΠϕϯτϦεφͷొ࿥(লུ)… const userAttention = useMemo(() => (isMouseHovered && isMouseMoving) || isTouchFocused, []); return { userAttention, containerElementRef, }; }; useUserAttension Ϣʔβʔ͕ϓϨʔϠʔʹ஫ҙΛҾ͍͍ͯΔ͔

Slide 50

Slide 50 text

export const ControlContainer = () => { const { seeking, paused } = useContext(PlaybackContext); const { userAttention, initialAttention } = useContext(PlayerFrameContext); const className = classNames('gyp-control-container', { 'is-active': userAttention || initialAttention || seeking || paused, }); return h`
...
`; }; ControlContainer (ίϯτϩʔϧόʔཁૉ) ෼ׂ͞ΕͨContextܦ༝ͰΧελϜϑοΫ͔Βͷ஋Λऔಘ ෳࡶͳॲཧͰ͕͢ɺͳͥίϯτϩʔϧόʔ͕දࣔ͞ΕΔ͔ ໌ࣔతʹهड़Ͱ͖Δ

Slide 51

Slide 51 text

6. ·ͱΊ

Slide 52

Slide 52 text

ө૾ϓϨʔϠʔͷಛ௃ͱɺෳࡶੑʹ͍ͭͯ Video ͷෳࡶͳঢ়ଶΛ ReactHooks Ͱ੍ޚ͢Δ hooksͷػߏ͸ɺ͜Ε·ͰϥΠϑαΠΫϧͷ੍໿ʹ્·Εͯࢄࡏ͍ͯͨ͠ঢ়ଶ ͷ؅ཧΛγϯϓϧʹ͢Δ ස౓ͱ໾ׂʹԠͯ͡ContextΛ෼ׂ؅ཧ͢Δ ReactHooksͰϓϨʔϠʔͷUIΛ࡞Γ͜Ή ϢʔβʔͷҰ࿈ͷૢ࡞ΛΧελϜϑοΫͰ·ͱΊͯ׆༻͢Δ

Slide 53

Slide 53 text

ΑΓਂ͘஌Δʹ͸ (ࢀߟจݙ) The Video Embed element https://developer.mozilla.org/ja/docs/Web/HTML/Element/video ಈը | Web | Google Developers https://developers.google.com/web/fundamentals/media/video?hl=ja Preventing rerenders with React.memo and useContext hook https://github.com/facebook/react/issues/15156 Building Your Own Hooks https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook HTML Media Events https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events