[英]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,我覺得我需要以某種方式重構以使用稱為withSVG
和withCanvas
鈎子。 他們設置了不同的 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 返回的組件)解構width
和height
。
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.