Reactの最新動向とベストプラクティス

45daf58c77e9dbbab5a1c8a5afc7ac5c?s=47 koba04
September 03, 2016

 Reactの最新動向とベストプラクティス

45daf58c77e9dbbab5a1c8a5afc7ac5c?s=128

koba04

September 03, 2016
Tweet

Transcript

  1. 3FBDUͷ࠷৽ಈ޲ͱϕετϓϥΫςΟε )5.-$POGFSFODF   !LPCB

  2. !LPCB

  3. 3FBDUࣄྫ

  4. 'BDFCPPL http://facebook.github.io/react/blog/2015/03/10/react-v0.13.html

  5. *OTUBHSBN

  6. /FUqJY

  7. 5XJUUFS NPCJMF

  8. "CFNBUW

  9. )ZQFSUFSN w IUUQTIZQFSUFSNPSH w IUUQTHJUIVCDPN[FJUIZQFSUFSN

  10. +FOLJOT%FTJHO-BOHVBHF w IUUQTHJUIVCDPNKFOLJOTDJKFOLJOTEFTJHOMBOHVBHF

  11. 3FBDU͸zࠓz࢖ΘΕ͍ͯΔϥΠϒϥϦʔ

  12. 3FBDUͷ͜Ε·Ͱ

  13. 2013 2014 2015 2016 Flux v0.13 ReactNative for iOS GraphQL

    Redux Relay React Native for Android v0.14 React Native for Windows v15.0.0 … React.Component Stateless Functional Component No more span and data-reactid React. PureComponent (v15.3.0ʙ)
  14. 3FBDUͷಛ௃

  15. 3FBDUͷಛ௃

  16. class App extends React.Component { constructor(…args) { super(…args); this.state =

    { text: ‘’, }; } render() { return ( <TextBox text={this.state.text} onChange={text => this.setState({text})} /> ); } } const TextBox = (text, onChange) => ( <div> <input type=“text” onChange={e => onChange(e.target.value} /> <p>{text}</p> </div> ); ReactDOM.render( <App />, document.getElementById(‘app’) );
  17. w 7JFX$PNQPOFOU 4UBUF  w $PNQPOFOU͸4UBUF͔Β7JFX 3FBDU&MFNFOU Λ࡞Δ w $PNQPOFOU͸7JFXΛ࡞Δؔ਺

    w 3FBDU͕ࠩ෼Λܭࢉͯ͠%0.ʹ൓ө͢Δ w *'͸1SPQT w એݴతʹ7JFXΛߏங͢Δ w એݴతʁ 3FBDUͷಛ௃
  18. 3FBDUͷಛ௃ State View Function Component 4UBUFΛߋ৽ 4UBUFΛ $PNQPOFOU ʹ౉͢ ࠩ෼Λ%0.

    ʹ൓ө ΠϕϯτʹΑΔ ߋ৽ॲཧ
  19. 3FBDUͷಛ௃ State View Function Component 4UBUFΛߋ৽ 4UBUFΛ $PNQPOFOU ʹ౉͢ ࠩ෼Λ%0.

    ʹ൓ө ΠϕϯτʹΑΔ ߋ৽ॲཧ Կ͕ى͖͍ͯΔͷ͔Θ͔Δ
  20. w ʮมԽʯͰ͸ͳ͘ʮঢ়ଶʯΛఆٛ͢Δ એݴతʁ // ໋ྩత // elͷมԽΛॻ͍͍ͯΔ button.on(‘click’, () =>

    el.append(child)); // એݴత // stateʹର͢Δ͋Δ΂͖දࣔΛॻ͍͍ͯΔ render = state => { el.innerHTML = state.map(child => `<div>${child}</div>`).join(‘’); }; button.on(‘click’, () => { state.push(child); render(state); }
  21. w ॳظදࣔ΋ߋ৽΋ৗʹ$PNQPOFOU 4UBUF Ͱ7JFXΛ࡞Δ એݴతʁ // ೖྗʹରͯ͠ৗʹಉ͡ग़ྗΛฦ͢ const CommentBox =

    ({comment, onChange}) => ( <div> <p>{comment}</p> <input type=“text” value={comment} onChange={e => onChange(e.target.value)} /> </div> ); const render = comment => ( ReactDOM.render( <CommentBox comment={comment} onChange={render} />, document.getElementById(‘app’) ) );
  22. $PNQPOFOUΛ࡞Δ

  23. w 4UBUFMFTT'VODUJPOBM$PNQPOFOUT w 3FBDU$PNQPOFOU w 3FBDU1VSF$PNQPOFOU w 3FBDUDSFBUF$MBTT $PNQPOFOUͷఆٛํ๏

  24. w 'JSTU$IPJDF w Πϯελϯε΋࣋ͨͳ͍ͨͩͷؔ਺ w 3FBDU&MFNFOU$PNQPOFOU 1SPQT  w /PTUBUF

    /PMJGFDZDMFNFUIPET /PSFGT w কདྷతͳ࠷దԽ΋ 4UBUFMFTT'VODUJPO$PNQPOFOUT 4'$ // PropsΛड͚औΓɺReactElementΛฦؔ͢਺ const Item = ({item}) => ( <div> <div>{item.name}×{item.count}</div> </div> ); // <Item item={{name: ‘foo’, count: 1}} />
  25. w 4UBUF΍ϥΠϑαΠΫϧϝιου͕ඞཁʹͳͬͨΒ 3FBDU$PNQPOFOU class App extends React.Component { constructor(…args) {


    super(…args); this.state = { user: null, }; } componentDidMount() { fetch(‘/api/user’) .then(res => res.json()) .then(user => this.setState({user})) ; } render() { if (this.state.user == null) return <Loading />; return ( <div> <User user={this.state.user} /> </div> ); }
  26. w 4UBUFʹ͸දࣔʹඞཁͳσʔλ͚ͩ 3FBDU$PNQPOFOU class App extends React.Component { constructor(…args) {


    super(…args); // this.state = { // timerId: null, // }; } componentDidMount() { this.timerId = setInterval(() => {}, 1000); // this.setState({ // timerId: setInterval(() => {}, 1000) // }); } componentWillMount() { clearInterval(this.timerId); // clearInterval(this.state.timerId); } render() { } }
  27. w 4IPVME$PNQPOFOU6QEBUFʹ1SPQTͱ4UBUFʹର͢Δ 4IBMMPX&RVBM͕ద༻͞ΕΔ w কདྷతʹ͸$IJMESFOͷ4'$ʹରͯ͠ͷ࠷దԽ͕ೖΔ͔΋ 3FBDU1VSF$PNQPOFOU Wʙ class Counter extends

    React.PureComponent { constructor(…args) { super(…args); this.state = {count: 0}; } render() { return ( <div> <p>{this.props.label}:{this.state.count}</p> <button onClick={() => this.setState({count: this.state.count + 1}) /> </div> ); } }
  28. 1VSF$PNQPOFOUͷམͱ݀͠ class Item extends React.PureComponent { render() { return (

    <div> <p>{this.props.name}</p> <button onClick={this.props.onClick}>click</button> {this.props.children} </div> ); } } // props.onClick !== nextProps.onClick <Item name=“foo” onClick={() => console.log(‘click’)} /> // props.children !== nextProps.children <Item name=“foo” onClick={onClick}> <div>foo</div> </Item>
  29. ਪଌ͢ΔͳܭଌͤΑ w SFBDUBEEPOTQFSG import Perf from ‘react-addons-perf’; Perf.start(); ReactDOM.render(<App name="React"

    />, el); setTimeout(() => { ReactDOM.render(<App name="React" />, el); Perf.stop(); Perf.printWasted(); }, 1000);
  30. w ͔ͭͯͷ࡞੒ํ๏ɻ؇΍͔ʹඇਪ঑΁ w ࠷ऴతʹ͸ผύοέʔδʹʁ w 'BDFCPPL಺෦΋3FBDU$PNQPOFOU΁ͷҠߦத w 3FBDUDSFBUF$MBTTͷศརػೳͷϚΠάϨʔγϣϯύε w NJYJO⾣)JHI0SEFS$PNQPOFOUT

    w BVUPCJOEJOH⾣1VCMJD$MBTT'JFMET 3FBDUDSFBUF$MBTT class Button extends React.Component { onClick = () => this.setState({count: this.state.count + 1}); } Stage2
  31. $PNQPOFOUΛ֦ு͢Δ

  32. w $PNQPTJUJPOPWFS*OIFSJUBODF w )JHIFS0SEFS'VODUJPO )JHIFS0SEFS$PNQPOFOUT // Կ͔͢Δؔ਺Λड͚औͬͯɺ݁ՌΛϩάग़ͯ͠ฦ͢ const logger =

    operation => (…args) => { const result = operation(…args); console.log(result); return result; }; const add = logger((a, b) => a + b); add(10, 20); // 30
  33. w )JHIFS0SEFS$PNQPOFOUT )JHIFS0SEFS$PNQPOFOUT // ComponentΛड͚औͬͯɺPureComponentͰϥοϓͯ͠ฦ͢ const pure = Component =>

    class Pure extends React.PureComponent {
 render() { return <Component …{this.props} />; } } const Item = ({name}) => <div>{name}</div>; const PureItem = pure(Item); // <PureItem name=“foo” />
  34. w BDEMJUFSFDPNQPTF w )JHIFS0SEFS$PNQPOFOUTͷVUJMJUZू w IUUQTHJUIVCDPNBDEMJUFSFDPNQPTF )JHIFS0SEFS$PNQPOFOUTΛ࢖͏ // isLoadedʹΑͬͯComponentΛग़͠෼͚Δ const

    enhance = branch( props => props.isLoaded, Component => Component, () => Loading ); const LoadUser = enhance(User); // <LoadUser isLoaded={isLoaded} user={user} />
  35. w SFBDUKTSFBDUSPVUFS XJUI3PVUFS  w SFBDUKTSFBDUSFEVY DPOOFDU )JHIFS0SEFS$PNQPOFOUTࣄྫ const MyPage

    = ({router}) => <div>hoge</div>; const WithRouterMyPage = withRouter(MyPage); const MyPage = ({user, updateName}) => <div>{user.name}</div>; const ConnectedMyPage = connect( mapStateToProps, mapDispatchToProps )(MyPage);
  36. w QSPQTDIJMESFOʹؔ਺Λ౉͢͜ͱͰ֦ு͢Δ w ແବͳ$PNQPOFOUʹΑΔϥοϓ͕ൃੜ͠ͳ͍ w 1SPQTͱͷিಥΛߟ͑ͳ͍͍ͯ͘ w ࠷దԽ͕೉͍͠ w SFBDUNPUJPO

    w IUUQTNFEJVNDPNNFSSJDLDISJTUFOTFOGVODUJPOBTDIJME DPNQPOFOUTGBBDF 'VODUJPOBT$IJME$PNQPOFOUT FuncAsChild = props => <div>{props.children(‘foo’)}</div>; // <FuncAsChild>{foo => <span>{foo}</span>}</FuncAsChild>
  37. 4UBUFΛ؅ཧ͢Δ

  38. w ΞϓϦέʔγϣϯͷঢ়ଶ͸ͳΔ΂͘ҰՕॴʹɻ w ਌ͷ$PNQPOFOU w ਌͸ࢠʹσʔλͱૢ࡞ʢؔ਺ʣΛ౉͢ɻࢠ͸ͦΕΒΛ࢖͏ͩ ͚ w ׬શʹ$PNQPOFOU಺ʹด͡Δঢ়ଶ͸$PNQPOFOUͷ4UBUFʹ͢ Δ͜ͱ΋ߟ͑Δ

    w ΞϓϦέʔγϣϯ͕େ͖͘ͳΔͱɺ਌ͷ$PNQPOFOUͰ؅ཧ͠ ͖Εͳ͘ͳΔ 4UBUF؅ཧ
  39. %BUBqPX EBUBΛ1SPQTͰ ౉͢ IBOEMFSͰ ΠϕϯτΛ఻೻

  40. %BUBqPX EBUBΛ1SPQTͰ ౉͢ IBOEMFSͰ ΠϕϯτΛ఻೻ ΞϓϦέʔγϣϯͷن໛͕ େ͖͘ͳ͖ͬͯͨΒʁ

  41. w 4UBUFΛ$PNQPOFOU͔Β੾Γ཭͢ w ΞϓϦέʔγϣϯͷঢ়ଶʢ4UBUFʣΛ4JOHMF4UPSFͰ؅ཧ w 4UBUFͷߋ৽Λ"DUJPOͱͯ͠දݱ͢Δ w 4UBUF͸"DUJPOͰߋ৽͞ΕΔ w 4UBUFͷߋ৽͸3FEVDFSͱݺ͹ΕΔ1VSF'VODUJPOͰ

    w $POUBJOFS$PNQPOFOUͱ1SFTFOUBUJPOBM$PNQPOFOU 3FEVY
  42. w 4UBUFΛ$PNQPOFOU͔Β੾Γ཭͢ w ΞϓϦέʔγϣϯͷঢ়ଶʢ4UBUFʣΛ4JOHMF4UPSFͰ؅ཧ w 4UBUFͷߋ৽Λ"DUJPOͱͯ͠දݱ͢Δ w 4UBUF͸"DUJPOͰߋ৽͞ΕΔ w 4UBUFͷߋ৽͸3FEVDFSͱݺ͹ΕΔ1VSF'VODUJPOͰ

    w $POUBJOFS$PNQPOFOUͱ1SFTFOUBUJPOBM$PNQPOFOU 3FEVY ඞཁʹͳΔ·Ͱ࢖͏ඞཁ͸ͳ͍
  43. %BUBqPX State

  44. w ಉ͡$PNQPOFOUͰ΋໾ׂ͸શ͘ҟͳΔ $POUBJOFS$PNQPOFOUͱ1SFTFOUBUJPOBM $PNQPOFOU Presentational Component w 7JFXͷߏஙΛ୲͏ w 4'$

    w %PNBJO-PHJDΛ஌Βͳ͍ w 4UBUF؅ཧͷ͜ͱ͸஌Βͳ͍ Container Component w ߋ৽ॲཧɺঢ়ଶ؅ཧΛ୲͏ w 3FBDU 1VSF $PNQPOFOU w %0.Λ஌Βͳ͍ w DPOOFDUͰ࡞੒ 3FEVY 
  45. Middleware 3FEVY State Action Creator &WFOU Reducer "DUJPO 4UBUF Selector

    4UBUF 1SPQT IO
  46. 3FEVY w BDUJPO"DUJPO$SFBUPS <FWFOU>  w ΞϓϦέʔγϣϯͰൃੜ͢ΔΠϕϯτ w OFX4UBUF3FEVDFS TUBUF

    BDUJPO  w ΞϓϦέʔγϣϯͷঢ়ଶߋ৽ w QSPQT4FMFDUPS TUBUF  w 7JFXʹඞཁͳσʔλ
  47. 3FEVY w ୯Ұͷ4UBUFʹશ͕ͯ٧·͍ͬͯΔ w ⾣4UBUFΛݟΕ͹ΞϓϦέʔγϣϯͷঢ়ଶ͕Θ͔Δ w ⾣7JFX$PNQPOFOU 4UBUF  w

    σʔλͱϩδοΫͷ෼཭ w ଟ͘ͷ෦෼͕෭࡞༻ͷͳ͍ؔ਺ʹͳΔͷͰςετ͕؆୯ w ෭࡞༻͸ʁʁ
  48. 3FEVY.JEEMFXBSF w ෭࡞༻΍ඇಉظॲཧ͸ɺ.JEEMFXBSFΛ࢖ͬͯॲཧ͢Δ w .JEEMFXBSFͰ͸ɺ3FEVDFS͕"DUJPOΛॲཧ͢ΔલޙʹׂΓ ࠐΈɺ"DUJPOͷՃ޻΍Ωϟϯηϧɺผͷ"DUJPOͷൃߦͳͲ ͕Մೳ w SFEVYUIVOL SFEVYQSPNJTF

    SFEVYTBHB SFEVY PCTFSWBCMF SFEVYMPPQ SFEVYF⒎FDUTʜ w SFEVYQFSTJTU SFEVYMPHHFS SFEVYBOBMZUJDT
  49. $PNQPOFOUΛςετ͢Δ

  50. w 5FTU6UJMTSFOEFS*OUP%PDVNFOU w %0.͕ඞཁͳςετ w 5FTU6UJMT4IBMMPX3FOEFS w $PNQPOFOUͷ୯ମςετ w SFBDUUFTUSFOEFS

    w $PNQPOFOU5SFFʹର͢Δςετ 5FTU
  51. w $PNQPOFOU୯ମʹର͢Δςετ͕Մೳ w ࢠ$PNQPOFOU͸SFOEFS͞Εͳ͍ w /PEF؀ڥͰςετ͕ՄೳʢKTEPNͳͲ͸ෆཁʣ w 3FGT͸ະαϙʔτɺ-JGFDZDMF.FUIPET͸Ұ෦ͷΈαϙʔτ w l4IBMMPXz3FOEFSJOH

    4IBMMPX3FOEFS const shallowRenderer = TestUtils.createRenderer(); const elementTree = shallowRenderer.render(<YourComponent />); assert(elementTree.props.children[0].type === ‘div’);
  52. w 3FBDU$PNQPOFOUTʹର͢Δςετͷ6UJMJUZ w TIBMMPX NPVOU SFOEFS w 5FTU6UJMTͷ"1*Λ࢖͏ΑΓɺ؆୯ʹɺΘ͔Γ΍͘͢ॻ͘͜ͱ͕ Մೳ BJSCOCFO[ZNF

    import {shallow} from ‘enzyme’; const wrapper = shallow(<YourComponent />); assert(wrapper.find(Link).prop(‘to’) === ‘/foo’); wrapper.find(‘button’).simulate(‘click’);
  53. w 3FBDU&MFNFOUͷπϦʔΛ+40/ʹͯ͠ฦ͢ w /PUl4IBMMPXz w -JGFDZDMF.FUIPET΋αϙʔτ͞Ε͍ͯΔ w "1*͸·ͩ·ͩ੔උத w +FTUͷTOBQTIPUUFTUJOHͰ࢖ΘΕ͍ͯΔ

    SFBDUUFTUSFOEFSFS Wʙ import renderer from ‘react-test-renderer’; const tree = renderer.create(<YourComponent />).toJSON(); assert(tree.props.children[0].type === ‘div’);
  54. ։ൃΛαϙʔτ͢Δπʔϧ

  55. w FTMJOUQMVHJOSFBDU w 3FBDUʹؔ͢Δ&4-JOUͷϧʔϧू w 3FBDUͷϕετϓϥΫςΟεΛ஌Δ͜ͱ͕Ͱ͖Δ w IUUQTHJUIVCDPNZBOOJDLDSFTMJOUQMVHJOSFBDU w FTMJOUQMVHJOKTYBZ

    w +49ʹର͢ΔBDDFTTJCJMJUZͷνΣοΫ͕Ͱ͖Δ w IUUQTHJUIVCDPNFWDPIFOFTMJOUQMVHJOKTYBZ &4-JOU3FBDU
  56. &4-JOU3FBDU

  57. &4-JOU3FBDU w OPTUSJOHSFGTʜจࣈྻʹΑΔ3FGTࢦఆͷېࢭ w QSFGFSTUBUFMFTTGVODUJPOʜ4'$ʹΑΔఆٛΛ༏ઌ͢Δ w OPEJSFDUNVUBUJPOTUBUFʜUIJTTUBUFΛ௚઀ߋ৽Λېࢭ w TPSUDPNQʜ$PNQPOFOU಺ͷϝιουఆٛॱΛνΣοΫ w

    KTYOPCJOEʜ1SPQTͰͷCJOE ΍"SSPX'VODUJPOͷېࢭ w KTYLFZʜLFZͷ1SPQT͕ඞཁͳ৔໘Ͱࢦఆ͞Ε͍ͯΔ͔ w 4FFNPSFSVMFT w IUUQTHJUIVCDPNZBOOJDLDSFTMJOUQMVHJOSFBDU
  58. 3FBDU4UPSZ#PPL w IUUQTHFUTUPSZCPPLJP w $PNQPOFOUΛΞϓϦέʔγϣϯ͔Β੾Γ཭ͨ͠ܗͰ։ൃͰ͖ Δ w 4UPSZͱͯ͠$PNQPOFOUͷදࣔύλʔϯΛఆٛͰ͖Δ w 4UPSZCPPLTJP

    w IUUQTTUPSZCPPLTJP
  59. 3FBDU%FWFMPQFS5PPMT w 3FBDU&MFNFOUͷ5SFFΛJOTQFDUͰ͖Δ w 4UBUFͷॻ͖׵͑΋Մೳ

  60. 3FBDU%FWFMPQFS5PPMT w 3FBDU&MFNFOUͷ5SFFΛJOTQFDUͰ͖Δ w 4UBUFͷॻ͖׵͑΋Մೳ

  61. 3FEVY%FW5PPMT w IUUQTHJUIVCDPNHBFBSPOSFEVYEFWUPPMT w λΠϜτϥϕϧσόοΪϯά w "DUJPOͷॻ͖׵͑ w IUUQTUXJUUFSDPNEBO@BCSBNPWTUBUVT 

  62. 3FEVY%FW5PPMT&YUFOTJPO w IUUQTHJUIVCDPN[BMNPYJTVTSFEVYEFWUPPMTFYUFOTJPO w ཤྺͷ&YQPSU*NQPSUɺςετέʔεͷ࡞੒ʜ

  63. 3FBM8PSMEͱ3FBDU

  64. 'BDFCPPLͱ3FBDU w 3FBDU͸'BDFCPPL͕࢖͏ͨΊʹ࡞ΒΕ͍ͯΔϥΠϒϥϦʔ w PWFS DPNQPOFOUT w l8FPOMZPQFOTPVSDFXIBUXFVTFz w 044ͱͯ͠ͷ3FBDU

    w 47( DVTUPNFMFNFOUT w GBDFCPPLJODVCBUPSDSFBUFSFBDUBQQ w SFBDUKTDPSFOPUFT
  65. 3FBM8PSMEͱ3FBDU w %FQSFDBUF1SPDFTT w ͭલͷϝδϟʔόʔδϣϯͰܯࠂ͔ͯ͠Βഇࢭ͞ΕΔ w ҠߦύεΛఏڙ w (SBEVBM"EPQUJPO w

    طଘͷΞϓϦέʔγϣϯʹ૊ΈࠐΈ΍͍͢"1*ͷఏڙ w 3FBDUXJUIK2VFSZ $BOWBTʜ w &TDBQF)BUDIFT w 3FGT EBOHFSPVTMZ4FU*OOFS)5.- $POUFYU
  66. 'VUVSF

  67. 3FBDU$PSF w $PSF͸ͲΜͲΜখ͘͞"1*͸࠷௿ݶʹ w SFBDU w $PNQPOFOU΍3FBDU&MFNFOUΛ࡞੒͢Δ w SFOEFSFS w

    $PNQPOFOUΛϓϥοτϑΥʔϜʹԠͯ͡ॲཧ͢Δ w %0.΋ͨͩͷλʔήοτ w SFBDUEPN SFBDUOBUJWF SFBDUBSUʜ
  68. % tree src -L 3 -d . !"" addons !""

    isomorphic # !"" children # !"" classic # !"" hooks # $"" modern !"" renderers # !"" art # !"" dom # # !"" client # # !"" fiber # # !"" server # # $"" shared # !"" native # !"" noop # !"" shared # # !"" fiber # # !"" hooks # # !"" shared # # !"" stack # # $"" utils # $"" testing !"" shared !"" test $"" umd
  69. <8*1>3FBDU'JCFS w ಺෦ΞϧΰϦζϜͷશ໘ॻ͖׵͑ 3FDPODJMFS  w ༏ઌ౓ʹԠͯ͡εέδϡʔϦϯά͞Εͨඇಉظͳ7JFXͷߋ৽ w ݱࡏ͸ࠩ෼ͷݕग़ɾద༻͕ಉظతʹߦͳΘΕ͍ͯΔ w

    NTҎ಺Λ໨ࢦͦ͏ͱ͢Δͱʜ w ༏ઌ౓ͷߴ͍ॲཧ SFRVFTU"OJNBUJPO'SBNF  w ༏ઌ౓ͷ௿͍ॲཧ SFRVFTU*EMF$BMMCBDL
  70. <8*1>3FBDU'JCFS // renderers/shared/fiber/ReactPriorityLevel.js module.exports = { // No work is

    pending. NoWork: 0, // For controlled text inputs. Synchronous side-effects. SynchronousPriority: 1, // Needs to complete before the next frame. AnimationPriority: 2, // Interaction that needs to complete pretty soon to feel responsive. HighPriority: 3, // Data fetching, or result from updating stores. LowPriority: 4, // Won't be visible but do the work in case it becomes visible. OffscreenPriority: 5, };
  71. 4FTTJPOBVUIPSl!LPCBz খ͘͞͸͡ΊͯɺඞཁʹԠͯ͡ΤίγεςϜΛ ར༻͠·͠ΐ͏ʂ 4FTTJPO TQFBLFSEFDLDPNLPCB