Reactjs 如何重构处理过多条件/用例的react组件?

Reactjs 如何重构处理过多条件/用例的react组件?,reactjs,data-structures,refactoring,javascript-objects,solid-principles,Reactjs,Data Structures,Refactoring,Javascript Objects,Solid Principles,我希望将可靠的原则应用于处理过多“用例”的react组件。例如,假设我有一个组件,它的主要职责是呈现如下表: return ( <Table dataSource="" name={tableName} /> ) 这只是一个例子。想象一下,一些dataSource的name属性嵌套了3层。然后,其他dataSource甚至会有不同的键名称(尽管我需要渲染的结果数据实际上是相同的)。不仅如此,根据数据源,我可能需要调用不同的端点来执行一些功能(同样,函数也在

我希望将可靠的原则应用于处理过多“用例”的react组件。例如,假设我有一个组件,它的主要职责是呈现如下表:

return (
   <Table dataSource="" name={tableName} />
)
这只是一个例子。想象一下,一些
dataSource
name
属性嵌套了3层。然后,其他
dataSource
甚至会有不同的键名称(尽管我需要渲染的结果数据实际上是相同的)。不仅如此,根据
数据源
,我可能需要调用不同的端点来执行一些功能(同样,函数也在做相同的事情,只是端点可能不同)。因此,在同一组件中,我将具有如下功能:

const exportTable = () => {
    if(dataSource === 'dataSourceA') {
        // use endpoint A
    } else if (dataSource=== 'dataSourceB') {
        // use endpoint B
    } else {
         // use endpoint C
    }
}

重构此类组件并使其更易于维护的最佳方法是什么?稍后,我们可以有10种类型的
数据源
,我不能在组件中使用if-else条件来满足它们的差异。

在纯功能风格中,您可以接受功能以及道具的普通对象:

if(props.name instanceof函数)
props.name=props.name(数据源)//或其他一些参数
通过这种方式,您可以轻松地将细节转移给消费者,而不是将所有内容都放在一个地方


那么,对于端点,为什么逻辑应该驻留在表组件中?保持纯粹的视觉效果,让家长传递细节。在React中,我们将视觉和业务逻辑保存在单独的组件中,以便您可以轻松地在应用程序的其他位置重用视图。

您可以使用挂钩来抽象数据的获取方式:

const{rows,…data}=useData(数据源)
返回(
);
useData
hook中:

函数useData(数据源){
如果(数据源=='dataSourceA'){
//使用端点A
}else if(数据源==='dataSourceB'){
//使用端点B
}否则{
//使用端点C
}
// ...
返回数据;
}
您仍然需要处理这些条件,但它们将与UI分离,这将使管理组件生命周期变得更容易

其次,您可以创建一个服务/API层来抽象数据获取

异步函数fetchFromEndpointA(args){ const response=等待httpClient .get(`/endpointA/${args}`) 返回响应.body; } API层将被钩子消耗:

//react async useAsync是帮助管理异步状态的库
从'react async'导入{useAsync};
函数useData(数据源){
const a=useAsync({promiseFn:fetchFromEndpointA,defer:true});
const b=useAncync({promiseFn:fetchFromEndpointB,defer:true});
如果(数据源=='dataSourceA'){
const{run,error,isLoading data}=a;
a、 run();
返回{错误,正在加载,数据};
}
// ...
}
您还可以从钩子中提取数据源解析+抓取。在不了解数据源对象的细节的情况下,我只能推荐一种通用策略。它可能看起来像:

异步函数获取数据(数据源,parseableObject){ 如果(数据源=='dataSourceA'){ 返回parseableObject['name']; }else if(数据源==='dataSourceB'){ const name=parseableObject[0][0]。name;//无论name的路径是什么 const data=wait callEndpointB(名称); 返回数据.result; }否则{ // ... } } 现在,任何钩子或组件都可以调用
actaindata
,而无需知道条件。钩子/组件只需要跟踪异步状态

例如,在挂钩中:

函数useData(数据源,可解析对象){
返回useAsync({promiseFn:()=>getaindata(dataSource,parseableObject)});
}
或者,只需在组件中调用它并完全放弃自定义挂钩:

const{rows;
返回(
);
在做出决定之前,你可能需要探索很多可能性

最后,关于重构的一些常见建议:

  • 在抽象或重构之前,首先通过可靠的、人类可读的测试来纠正所有具体的高级行为。快速和肮脏的代码是好的。不要依赖于测试实现细节或内部抽象。然后,如果以后出现了清晰的模式,您可以使用现有的测试进行重构来指导您

  • 考虑一下成本。有一句程序员的谚语,大意是“没有抽象比有错误的抽象要好”。如果你决定将代码重新组织到不同的层中,你需要主动意识到它对可维护性的影响,等等。请查看。与其让我在这里总结,不如让你看/读它,并收集自己的见解

    • 我喜欢。它很整洁,很好地抽象事物

      或者,我已经完成了您在过去的
      useffect
      函数中描述的操作。
      注意:
      usemo
      可能也有理由,但我将重点介绍
      useffect

      从“../util/for/table/data”导入{parseTableData,TableData};
      界面道具{
      data:TableData;//键入这个将非常有用
      名称:字符串;
      }
      常量表:React.FC=({name,data})=>{
      const[tableData,setTableData]=useState();//在init上未定义
      使用效果(
      ()=>parseTableData(setTableData,data),
      [数据,可设置数据]
      );
      如果(!tableData){
      返回解析…请稍候。

      } //在这里,您可以使用'tableData',因为它已正确格式化 返回。。。 }
      然后,您可以将解析器逻辑抽象到单独的文件中:

      接口表数据{
      ...
      }
      导出常量parseTableData=(
      可设置数据:
      
      const exportTable = () => {
          if(dataSource === 'dataSourceA') {
              // use endpoint A
          } else if (dataSource=== 'dataSourceB') {
              // use endpoint B
          } else {
               // use endpoint C
          }
      }