React:组件的抽象。合成 vs 渲染道具
React: Abstraction for components. Composition vs Render props
长问题请准备好
我最近一直在使用 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
。
这就是我的困惑所在。 wrapper 中的 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>
)
}
这按预期工作。并且仅当状态不是 loading
或 error
.
时才会呈现子项
我仍然很困惑,为什么第一种方法在明确执行 UI 事件时不显示这些元素?
Codesandbox link 复制行为: https://codesandbox.io/s/react-composition-and-render-prop-tyyzh?file=/src/App.js
好的,所以我想通了,它比听起来更简单。
在方法一中:JSX 仍将被执行,因为它是一个函数调用 React.createElement
。
但是,Wrapper
仅在查询成功时返回 children。因此,children 在 UI.
上将不可见
这两种方法都有效,但使用方法 1,我们可能必须处理 undefined
数据。
我最终使用 render-prop 作为我的解决方案,因为它看起来更干净。
长问题请准备好
我最近一直在使用 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
。
这就是我的困惑所在。 wrapper 中的 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>
)
}
这按预期工作。并且仅当状态不是 loading
或 error
.
我仍然很困惑,为什么第一种方法在明确执行 UI 事件时不显示这些元素?
Codesandbox link 复制行为: https://codesandbox.io/s/react-composition-and-render-prop-tyyzh?file=/src/App.js
好的,所以我想通了,它比听起来更简单。
在方法一中:JSX 仍将被执行,因为它是一个函数调用 React.createElement
。
但是,Wrapper
仅在查询成功时返回 children。因此,children 在 UI.
这两种方法都有效,但使用方法 1,我们可能必须处理 undefined
数据。
我最终使用 render-prop 作为我的解决方案,因为它看起来更干净。