ReactHooks 사용하기

11235 단어 Reactreact-hooks
이 기사는 Nextremer Advent Calendar 2018의 9 일째 기사입니다.

우리의 대화 시스템인 견습생 의 프런트를 ReactHooks를 사용해 만들어 보았습니다.

소개



ReactHooks에서 제공하는 API 중
- useState
- useContext
- useMemo
의 3개를 사용하고 있습니다.
또 각 API의 상세한 설명은 그 밖에 얼마든지 양 기사가 구르고 있으므로 이 기사에서는 할애합니다.

만들어 보자



준비



npm 모듈 설치



평소
이번에는 편하고 싶기 때문에 모듈 번들러에 parcel을 사용하고 있습니다. parcel 슈퍼 편리
$ mkdir react-hooks-minarai-sample && cd $_
$ npm init -y
$ npm i -S react@next react-dom@next
$ npm i -D parcel-bundler

minarai를 이동하는 데 필요한 것을 설치
minarai는 Socket.IO를 사용하기 때문에 Socket. IO 클라이언트 및 minarai용 SDK 설치
$ npm i -S socket.io-client minarai-client-sdk-js-socket-io

나중에 디자인 주위
$ npm i -S styled-components @material-ui/core

minarai 용 Context 만들기



Socket.IO에서 minarai의 다양한 이벤트를 수신하기위한 Context를 만듭니다.

우선 MinaraiContext를 정의

src/js/contexts/minarai.js
const MinaraiContext = createContext()

커스텀 Provider를 작성.
이 Context에서는, 송신 메세지, 수신 메세지, 송신 메소드의 3 개를 제공합니다.

src/js/contexts/minarai.js
const MinaraiContextProvider = ({ children }) => {
  const [outgoingMessage, setOutgoingMessage] = useState('')
  const [incomingMessage, setIncomingMessage] = useState('')
  const send = msg => {}
  return (
    <MinaraiContext.Provider value={{ outgoingMessage, incomingMessage, send }}>
      {children}
    </MinaraiContext.Provider>
  )
}

이번은 단순히 송신 이벤트, 수신 이벤트만을 워치해, 각각의 메세지용의 로컬 스테이트를 갱신하도록(듯이) 하고 있습니다.

src/js/contexts/minarai.js
const MinaraiContextProvider = ({ children }) => {
  const [outgoingMessage, setOutgoingMessage] = useState('')
  const [incomingMessage, setIncomingMessage] = useState('')

  // minarai-clientの作成
  const cli = new MinaraiClient({/* 略 */})
  cli.on('sync', data => setOutgoingMessage(data.body.message))
  cli.on('message', data => setIncomingMessage(data.body.messages[0].utterances[0].text))
  cli.init()

  const send = msg => cli.send(msg)

  return (
    <MinaraiContext.Provider value={{ outgoingMessage, incomingMessage, send }}>
      {children}
    </MinaraiContext.Provider>
  )
}

이것으로 컨텍스트는 완성. . .

라고 생각했습니다만, 이 구현이라고 Provider가 불려 갈 때마다 이벤트가 바인드 되므로, 송수신할 때마다 이벤트 발화 횟수가 늘어나 버립니다.

MinaraiClient의 생성, 이벤트 바인드의 처리를 최초회만 실시하도록(듯이) 수정합니다.
ReactHooks의 useMemo를 사용하면 쉽게 할 수 있습니다

src/js/contexts/minarai.js
  export const MinaraiContextProvider = ({ children }) => {
    const [outgoingMessage, setOutgoingMessage] = useState('')
    const [incomingMessage, setIncomingMessage] = useState('')

  // minarai-clientの作成
+   const minaraiClient = useMemo(() => {
      const cli = new MinaraiClient({/* 略 */})
      cli.on('sync', data => setOutgoingMessage(data.body.message))
      cli.on('message', data => setIncomingMessage(data.body.messages[0].utterances[0].text))
      cli.init()
+     return cli
+   }, [])

-   const send = message => cli.send(message)
+   const send = message => minaraiClient.send(message)

    return (
      <MinaraiContext.Provider value={{ outgoingMessage, incomingMessage, send }}>
        {children}
      </MinaraiContext.Provider>
    )
  }
useMemo 의 제 2 인수에 빈 배열을 건네주는 것으로 최초회만 동작시킬 수가 있습니다.
같은 처리는 useEffect 를 사용하는 것도 가능합니다만, 이번은 클라이언트 인스턴스를 반환하고 싶었으므로 useMemo 를 사용하고 있습니다.

minaraiContext 포함



우선은 루트 컴퍼넌트로 ContextProvider로 랩 해 줍니다.

src/js/components/App.js
+ import { MinaraiContextProvider } from '../contexts/minarai'

  return (
+   <MinaraiContextProvider>
      <Main>
        略
      </Main>
+   </MinaraiContextProvider>
  )

그리고는 사용하는 컴퍼넌트로 적절히 useContext 하고 하면 OK입니다.

src/js/components/Form.js
+ import { MinaraiContext } from '../contexts/minarai'

  export default () => {
    const [text, setText] = useState('')
+   const { send } = useContext(MinaraiContext)

    return (
      <Wrapper>
        <Input value={text} onChange={e => setText(e.target.value)} />
-       <SendButton color="primary">
+       <SendButton color="primary" onClick={() => send(text)}>
          Send
        </SendButton>
      </Wrapper>
    )
  }

src/js/components/Messages.js
+ import { MinaraiContext } from '../contexts/minarai'

  export default () => {
+   const { outgoingMessage, incomingMessage } = useContext(MinaraiContext)
    return (
      <Wrapper>
        <MessageBalloon align="left">
-         <OutgoingMessage>test</OutgoingMessage>
+         <OutgoingMessage>{outgoingMessage}</OutgoingMessage>
        </MessageBalloon>
        <MessageBalloon align="right">
-         <IncomingMessage>test</IncomingMessage>
+         <IncomingMessage>{incomingMessage}</IncomingMessage>
        </MessageBalloon>
      </Wrapper>
    )
  }

만든 것은 여기에 있습니다.
htps : // 기주 b. 코 m / k- 단지 / Rea ct-hoo ks- 미라 - mp ぇ

좋은 웹페이지 즐겨찾기