繁体   English   中英

是否可以将此 HoC 模式转换为 React Hook 语法?

[英]Is it possible to turns this HoC pattern into a React Hook syntax?

我正在尝试创建一个可重用的组件,它会改变它的行为——本质上是渲染到 SVG 或 Canvas。 我目前正试图通过将它包装在一个 HoC 中来做到这一点(但是我正在尝试使用 React 钩子),所以这一切都显得有些平淡。


使用额外信息进行编辑

使用当前方法(HoC 返回函数),我收到以下错误:

函数作为 React 子元素无效。 如果您返回 Component 而不是从 render 返回,则可能会发生这种情况。 或者,您可能打算调用此函数而不是返回它。

如果我删除了 HoC 中的函数调用:

React.jsx:类型无效——需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:对象


我已经看到了一个将 HoC 转换为 React 钩子的例子,但我正在努力弄清楚如何转换它 - 如果它甚至可能并且想知道是否有人可以给我一个指针? 我可能试图以错误的方式构建它,因为它感觉像是一个相当复杂的用例。

所以我现在有这两个 HoC,我觉得我需要以某种方式重构以使用称为withSVGwithCanvas钩子。 他们设置了不同的 DOM 来表示,重要的是有一个叫做renderLoop的函数,它需要从下面的 Scatter 组件中调用。

有点古怪,因为Scatter现在只是业务逻辑(利用 useEffect 中的依赖项),它实际上不需要返回任何 DOM,因为它只是操作父 HoC 的 DOM。 我期待在未来有更多像Scatter这样的组件,所以不想把这个逻辑移到 HoCs 中(如果他们甚至是这样做的正确方法)。

 const duration = 2000; const withSVG = ({ width, height, ...props }) => WrappedComponent => { const layer = useRef(null); return (props) => ( <g width={width} height={height} ref={layer}> <WrappedComponent {...props} layer={layer} /> </g> ); }; const withCanvas = ({ width, height, ...props }) => WrappedComponent => { const layer = useRef(null); const canvas = useRef(null); const renderLoop = getRenderLoop(canvas.current, width, height); return (props) => ( <React.Fragment> <custom ref={layer}/> <canvas width={width} height={height} ref={canvas}></canvas> <WrappedComponent {...props} layer={layer} renderLoop={renderLoop} /> </React.Fragment> ); }; const Scatter = ({ data, layer, renderLoop }) => { useEffect(() => { if (!layer.current) { return; } // D3 data join const join = d3 .select(layer.current) .selectAll("circle") .data(data, d => d.key); // Shrink the circles to 0 size const exit = join.exit() .transition("radius") .duration(duration) .attr("r", 0) .remove(); const enter = join.enter() .append("circle") .attr("cx", d => dx) .attr("cy", d => dy) .attr("r", 0) .style("fill", d => d.color); const update = enter .merge(join) .transition("radius") .duration(duration) .attr("cx", d => dx) .attr("cy", d => dy) .attr("r", 30) .style("fill", d => d.color); if (renderLoop) { renderLoop(exit, update); } }, [layer, data]); return null; }; const CanvasScatter = withCanvas(Scatter); const SVGScatter = withSVG(Scatter); // index.js const width = 400; const height = 400; const App = () => { const [data, setData] = useState([ { key: 1, x: 50, y: 50, color: "red" }, { key: 2, x: 150, y: 150, color: "blue" }, ]); setTimeout(() => { setData([ { key: 1, x: 100, y: 100, color: "orange" }, { key: 3, x: 150, y: 50, color: "green" }, ]); }, 3000); return ( <div> <svg width={width} height={height}> <SVGScatter width={width} height={height} data={data} /> </svg> <CanvasScatter width={width} height={height} data={data} /> </div> ); // return <div>Hello React,Webpack 4 & Babel 7!</div>; }; ReactDOM.render(<App />, document.querySelector("#root"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div id="root"></div>

问题

我认为您的高阶组件格式不正确。 看起来你已经定义了它们来消耗一些道具,然后是一个要包装的组件。

const withSVG = ({ width, height, ...props }) => WrappedComponent => {...}

但是您按预期调用它们

const SVGScatter = withSVG(Scatter);

这里首先使用Scatter组件,HOC 尝试从中解构值并返回一个函数来使用一个undefined的组件。 我认为这会导致您看到的错误。

解决方案

基于你如何使用装饰组件

<SVGScatter width={width} height={height} data={data} />
<CanvasScatter width={width} height={height} data={data} />

我认为您的意思是从内部组件(由 HOC 返回的组件)解构widthheight

const withSVG = WrappedComponent => ({ width, height, ...props }) => {
  const layer = useRef(null);

  return (
    <g width={width} height={height} ref={layer}>
      <WrappedComponent
        layer={layer}
        {...props} // <-- data passed here
      />
    </g>
  );
};

const withCanvas = WrappedComponent => ({ width, height, ...props }) => {
  const layer = useRef(null);
  const canvas = useRef(null);
  const renderLoop = getRenderLoop(canvas.current, width, height);

  return (
    <React.Fragment>
      <custom ref={layer}/>
      <canvas width={width} height={height} ref={canvas}></canvas>
      <WrappedComponent
        layer={layer}
        renderLoop={renderLoop}
        {...props} // <-- data passed here
      />
    </React.Fragment>
  );
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM