javascript - 是否可以将这种 HoC 模式转换为 React Hook 语法?
问题描述
我正在尝试创建一个可重用的组件,它会改变它的行为——本质上是渲染为 SVG 或 Canvas。我目前正试图通过将它包装在一个 HoC 中来做到这一点(但是我正在尝试使用 React 钩子),所以这一切都变得有点平淡。
编辑额外信息
使用当前方法(HoC 返回一个函数)我收到以下错误:
函数作为 React 子级无效。如果您返回一个组件而不是从渲染中返回,则可能会发生这种情况。或者,也许您打算调用此函数而不是返回它。
如果我删除 HoC 中的函数调用:
React.jsx:类型无效 - 需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:对象
我已经看到了一个将 HoC 转换为 React 钩子的示例,但我正在努力弄清楚如何转换它 - 如果它甚至可能的话,并且想知道是否有人可以给我一个指针?我可能试图以错误的方式构建它,因为它感觉像是一个相当复杂的用例。
所以我现在有这两个 HoC,我觉得我需要以某种方式重构以使用称为withSVG
and的钩子withCanvas
。他们设置了不同的 DOM 来表示,重要的是有一个调用的函数renderLoop
,需要从下面的 Scatter 组件中调用。
有点古怪,因为它Scatter
现在只是业务逻辑(利用 useEffect 中的依赖项),它实际上不需要返回任何 DOM,因为它只是在操作父 HoC 的 DOM。我期待Scatter
在未来会有更多的组件,但是所以不想将这个逻辑移动到 HoC 中(如果它们甚至是这样做的正确方法)。
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 => d.x)
.attr("cy", d => d.y)
.attr("r", 0)
.style("fill", d => d.color);
const update = enter
.merge(join)
.transition("radius")
.duration(duration)
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.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} />
我认为您的意思是从内部组件中解构width
,height
即 HOC 返回的组件。
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>
);
};
推荐阅读
- java - MainActivity -> 链接引用失败
- kubernetes - Traefik 无法在 k8s api 上读取
- ios - 出现键盘时约束不更新
- java - 如何创建这样格式的 Java HTTP 请求?
- jsf - 以动态方式为我的 JSF 应用程序上传新的徽标图像
- sql - 使用查询构建器根据条件对表中的同一列进行排序,具有不同的排序顺序
- android - 如何使 Firebase 数据库规则只允许 10 的增量
- asp.net-web-api - 使用 nhibernate orm 进行分布式缓存
- python - matplotlib get_color 用于子图
- android - React Native - 准确的当前位置(纬度,经度)