React:组件的抽象.合成vs渲染道具



长问题请准备好

我最近一直在使用react-query,并发现许多代码必须为使用useQuery的每个组件复制。例如:

if(query.isLoading) {
return 'Loading..'
}
if(query.isError) {
return 'Error'
}
if(query.isSuccess) {
return 'YOUR ACTUAL COMPONENT'
}

我尝试创建一个包装器组件您将查询信息传递给它,它将为您处理所有状态。

基本实现如下:

const Wrapper = ({ query, LoadingComponent, ErrorComponent, children }) => {
if (query.isLoading) {
const toRender = LoadingComponent || <DefaultLoader />;
return <div className="grid place-items-center">{toRender}</div>;
}
if (query.isError) {
const toRender = ErrorComponent ? (
<ErrorComponent />
) : (
<div className="dark:text-white">Failed to Load</div>
);
return <div className="grid place-items-center">{toRender}</div>;
}
if (query.isSuccess) {
return React.Children.only(children);
}
return null;
};

const Main = () => {
const query = useQuery(...);
return (
<Wrapper query={query}>
<div>{query.message}</div>
</Wrapper>
)
}

问题是query.message可能是未定义的,因此会抛出错误。无法读取未定义的属性消息

但是,它应该可以通过可选的链接query?.message来修复。

这就是我困惑的地方。包装器内的UI元素应该已经呈现,但它们没有。如果没有,为什么会抛出错误呢?

这意味着,包装器的chilren在每次呈现时执行。但看不见。为什么? ?

渲染道具营救

包装器>
const WrapperWithRP = ({ query, children }) => {
const { isLoading, data, isError, error } = query;
if (isLoading) return 'Loading...'
if (isError) return 'Error: ' + error
return children(data)
}

然后像这样使用

const Main = () => {
const query = useQuery(...);
return (
<Wrapper query={query}>
{state => {
return (
<div>{state.message}</div>
)
}
}
</Wrapper>
)
}

按预期工作。只有当状态不是loadingerror时,才会呈现子控件。

我仍然很困惑,为什么第一种方法不显示元素的UI事件,当他们清楚地执行?

Codesandbox链接复制行为:https://codesandbox.io/s/react-composition-and-render-prop-tyyzh?file=/src/App.js

好吧,我算出来了,这比听起来简单多了。

方法一:JSX仍然会被执行,因为它是一个函数调用React.createElement。但是,Wrapper只在查询成功时返回子节点。因此,子元素在UI上是不可见的。

两种方法都可以,但是对于方法1,我们可能需要处理undefined数据。

我最终使用render-prop作为我的解决方案,因为它看起来更干净。

最新更新