DigitalFlop = ({ config = {}, className, style }) => {
  const domRef = useRef(null)
  const rendererRef = useRef(null)
  const graphRef = useRef(null)

  function getGraph(mergedConfig) {
    const { animationCurve, animationFrame } = mergedConfig

    return rendererRef.current.add({
      name: 'numberText',
      animationCurve,
      animationFrame,
      shape: getShape(mergedConfig),
      style: getStyle(mergedConfig)
    })
  }

  function getShape({ number, content, toFixed, textAlign, rowGap, formatter }) {
    const [w, h] = rendererRef.current.area

    const position = [w / 2, h / 2]

    if (textAlign === 'left') position[0] = 0
    if (textAlign === 'right') position[0] = w

    return { number, content, toFixed, position, rowGap, formatter }
  }

  function getStyle({ style, textAlign }) {
    return deepMerge(style, {
      textAlign,
      textBaseline: 'middle'
    })
  }

  useEffect(() => {
    const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {})

    if (!rendererRef.current) {
      rendererRef.current = new CRender(domRef.current)

      graphRef.current = getGraph(mergedConfig)
    }

    const graph = graphRef.current
    graph.animationEnd()

    const shape = getShape(mergedConfig)

    const cacheNum = graph.shape.number.length
    const shapeNum = shape.number.length

    cacheNum !== shapeNum && (graph.shape.number = shape.number)

    const { animationCurve, animationFrame } = mergedConfig

    Object.assign(graph, { animationCurve, animationFrame })

    graph.animation('style', getStyle(mergedConfig), true)
    graph.animation('shape', shape)
  }, [config])

  const classNames = useMemo(() => classnames('dv-digital-flop', className), [
    className
  ])

  return (
    <div className={classNames} style={style}>
      <canvas ref={domRef} />
    </div>
  )
}
@description CRender animationFrame
@type {String}
@default animationFrame = 50