React/Redux와 요소를 결합하여 사용

9091 단어 캔버스Reactredux

개요



redux의 store 의 내용을 사용하여 <canvas> 요소를 그리고 싶었는데 보통으로 해도 잘되지 않았으므로 해결 방법을 메모해 둡니다. 문제의 원인은 <canvas> 의 내용을 괴롭히는 경우는 DOM을 직접 조작할 필요가 있으므로, 근본적으로 react와 궁합이 나쁜 것입니다. 일단 적당하게 검색하고 있으면 나왔다.

결론


<canvas> 의 묘화는 최초회만 react로부터 실시해, 그 후에는 react로부터 직접은 만지지 않도록 한다. 이를 위해 <canvas> 요소를 포함하는 React.Component
  • <canvas> 요소를 ref로 설정하고
  • componentDidMount() 에서 context 의 설정과 첫 그리기를,
  • shouldComponentUpdate() 에서 ref 로부터 직접 DOM을 조작해 묘화 내용의 갱신을 실시해, false

  • 데모



    간단한 예로, 양식에 입력한 텍스트를 <canvas> 에 이미지로 그려야 합니다.

    react와 d3.js를 결합하는 예

    코드



    코드는 github ( ) 에 있습니다. 이하, 간단히 설명합니다.

    먼저 다음과 같이 index.js 에서 reducerstore 를 정의해 둡니다. state 의 구조는 매우 간단하며 양식에 입력된 텍스트(= <canvas> 에 그리려는 텍스트)의 내용만 관리합니다.

    index.js
    import React from 'react'
    import ReactDOM from 'react-dom'
    import { createStore } from 'redux'
    import { Form, Canvas } from './components'
    
    const initialState = {text: ''}
    const reducer = (state = initialState, action) => {
        switch (action.type) {
            case 'CHANGE_TEXT':
                return {
                    ...state,
                    text: action.text
                }
            default:
                return state
        }
    }
    
    const store = createStore(reducer)
    
    const render = () => {
        ReactDOM.render(
            <div>
                <Form store={store}/>
                <Canvas store={store}/>
            </div>,
            document.getElementById('root')
        )
    }
    
    store.subscribe(() => render())
    render()
    

    이하, render() 내부에서 사용하고 있는 <Form /><Canvas /> 를 정의해 갑니다. 우선 <Form /> 에 대해서는 보통으로 쓰면 됩니다.

    components.js
    import React, { Component } from 'react'
    
    export const Form = ({ store }) => {
      const { text } = store.getState()
      return (
        <div>
          <input 
            value={text} 
            onChange={e => store.dispatch({
              type: 'CHANGE_TEXT',
              text: e.target.value
            })}
          />
        </div>
      )
    }
    

    보통입니다. <input>valuestore
    다음으로, 문제가 되는 dispatch 요소를 포함한 <canvas> 컴퍼넌트입니다.

    components.js에 추가
    const canvasWidth = 300
    const canvasHeight = 50
    
    export class Canvas extends Component {
      componentDidMount() {
        this.ctx = this.refs.canvas.getContext('2d')
        this.ctx.textAlign = 'center'
        this.ctx.font = '24px sans-serif'
    
            const { text } = this.props.store.getState()
            this.ctx.fillText(text, canvasWidth / 2, canvasHeight / 2)
      }
      shouldComponentUpdate() {
        const { text } = this.props.store.getState()
    
        this.ctx.clearRect(0, 0, canvasWidth, canvasHeight)
        this.ctx.fillText(text, canvasWidth / 2, canvasHeight / 2)
    
        return false
      }
    
      render() {
        return (
          <div>
            <canvas ref="canvas" width={canvasWidth} height={canvasHeight} />
          </div>
        )
      }
    }
    

    이런 식으로, <Canvas /> 내부에서 기본적인 설정과 묘화를 실시해, componentDidMount() 내부에서 shouldComponentUpdate()의 상태를 store에 반영하는 것으로 잘 움직였습니다. 이 방법이라면 redux <canvas>가 업데이트 될 때마다 store가 불려 그 안에서 직접 DOM을 조작하고 그 후 shouldComponentUpdate()를 반환하기 때문에 react는 더 이상 false를 변경하지 않는다는 것이 가능합니다.

    좋은 웹페이지 즐겨찾기