在 reactjs 中实现基于 INTERFACE 的功能以基于变量呈现组件

Posted

技术标签:

【中文标题】在 reactjs 中实现基于 INTERFACE 的功能以基于变量呈现组件【英文标题】:Implement INTERFACE based functionality in reactjs to render component based on variable 【发布时间】:2022-01-20 20:28:22 【问题描述】:

如何使用基于界面的功能来根据选项卡选择呈现组件。

假设我有 3 个组件,即

    OneTimeOnlyScheduleComponent DailyScheduleComponent WeeklyScheduleComponent

我想要某种功能,所有这些组件都实现接口InterfaceBasedComponent

例如

    OneTimeOnlyScheduleComponent implements InterfaceBasedComponent DailyScheduleComponent implements InterfaceBasedComponent WeeklyScheduleComponent implements InterfaceBasedComponent

在 ReactJS 中,我应该能够使用工厂模式或其他方式创建对象。

GitHub Code Hosted UI

/* TAB BUTTONS */
<ul className="nav nav-tabs border-bottom-0" role="tablist">

    freqType.map(freq => 
        return (
            ![64, 128].includes(freq.key) &&
            <li key=freq.key className="nav-item">
                <a href="#freqType1" property_name="freq_type" 
                    className="nav-link " + (state.freq_type === freq.key ? 'active' : '')
                    onClick=(e) => scheduleTypeChange(freq.key)
                    data-toggle="tab" role="tab" 
                    aria-controls="freqType1" 
                    aria-selected=state.freq_type === freq.key>
                    freq.value</a>
            </li>)
    )

</ul>

根据上面的代码,当用户点击其中一个选项卡时,应该会生成相应的组件。

<div className="tab-content border">
    /* One time schedule */
    <div className="m-2 tab-pane fade " + (state.freq_type === 1 ? showClass : hiddenClass) id="freqType1" role="tabpanel">
        <OneTimeOnlyScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Daily schedule */
    <div className="m-2 tab-pane fade " + (state.freq_type === 4 ? showClass : hiddenClass) id="freqType4" role="tabpanel">
        <DailyScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Weekly schedule */
    < div className="m-2 tab-pane fade " + (state.freq_type === 8 ? showClass : hiddenClass) id="freqType8" role="tabpanel">
        <WeeklyScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Monthly schedule */
    < div className="m-2 tab-pane fade " + (state.freq_type === 16 ? showClass : hiddenClass) id="freqType16" role="tabpanel">
        <MonthlyScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Monthly relative schedule */
    <div className="m-2 tab-pane fade " + (state.freq_type === 32 ? showClass : hiddenClass) id="freqType32" role="tabpanel">
        <MonthlyRelativeScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Yearly schedule */
    <div className="m-2 tab-pane fade " + (state.freq_type === 64 ? showClass : hiddenClass) id="freqType64" role="tabpanel">
        <YearlyScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
    /* Year long schedule */
    <div className="m-2 tab-pane fade " + (state.freq_type === 128 ? showClass : hiddenClass) id="freqType128" role="tabpanel">
        <YearLongScheduleComponent schedule=state onComponentChange=commonScheduleChangeHandler />
    </div>
</div>

理想情况下,我希望简化代码以使用基于接口的对象渲染,例如InterfaceBasedComponent。这个接口应该可以创建所需组件的对象。

<div className="tab-content border">

    freqType.map(freq => 
    return (
       ![64, 128].includes(freq.key) &&                     
       <div className="m-2 tab-pane fade " + (state.freq_type === freq.key ? showClass : hiddenClass) 
          id="freqType" + freq.key 
          role="tabpanel">
          <InterfaceBasedComponent schedule=state onComponentChange=commonScheduleChangeHandler />
      </div>
  )            

</div >

【问题讨论】:

React 支持composition over inheritance,值得一读。 【参考方案1】:

你说:

我应该能够使用工厂模式创建对象 ... 我想简化我的代码以使用基于接口的对象 渲染

但是您实际上想要简化什么? (例如,工厂不是接口)。

接口

如果你明确想使用接口,那是不可能的,因为 javascript 没有接口,所以 React 也没有。

(有interfaces in Typscript,但我确定不是你的意思)

工厂

但是你可以很好地使用工厂函数来创建组件:

const OneTimeOnlyScheduleComponent = ( props ) => 
    return <>
        <p>( specific stuff to OneTimeOnlyScheduleComponent )</p>
         props.children 
    </>;
;

const DailyScheduleComponent = ( props ) => 
    return <>
        <p>( specific stuff to DailyScheduleComponent )</p>
         props.children 
    </>;
;

export const ListFactory = ( props: IProps ) => 
    const  schedule  = props;

    const List = <ul>
         schedule.list.map( item => <li key= item.key > item.value </li> ) 
    </ul>;

    switch( schedule.type )
        case 'onetime': return <OneTimeOnlyScheduleComponent> List </OneTimeOnlyScheduleComponent>;
        case 'daily':   return <DailyScheduleComponent> List </DailyScheduleComponent>;
        default:
            return 'error';
    
;

function App()
    const [ schedule, setSchedule ] = useState(  type: 'onetime', list: list  );

    return <div>
        <button onClick= () =>  setSchedule(  type: 'daily', list: list  ); >
            switch
        </button>
        <ListFactory schedule= schedule  />
    </div>;

HOC

React 中也有Higher-Order Components (HOC),或许可以解决 从某种意义上说,问题更像是接口的作用......但我不明白在这种情况下这会对你有什么帮助。

例如您可能有一个名为 implementsList 的 HOC,但是您的所有组件确实应该实现该列表,所以您 使用这种方法不会消除代码重复:

export const OneTimeOnlyScheduleComponent = implementsList(( props ) => 
    return <><p>( specific stuff to OneTimeOnlyScheduleComponent )</p>
        <ul>
             props.list.map( item => <li key= item.key > item.value </li> ) 
        </ul>
    </>;
);

export const DailyScheduleComponent = implementsList(( props ) => 
    return <><p>( specific stuff to DailyScheduleComponent )</p>
        <ul>
             props.list.map( item => <li key= item.key > item.value </li> ) 
        </ul>
    </>;
);

function implementsList(WrappedComponent) 
    return function( props )
        return <>
            <p>type:  props.schedule.type </p>
            <WrappedComponent list= props.schedule.list  />
        </>;
    ;

顺便说一句:按照惯例,HOC 应该以前缀with... 命名,因此在这种情况下,HOC 最好命名为withList, 这也更好地代表了使用 HOC 的意图。

【讨论】:

以上是关于在 reactjs 中实现基于 INTERFACE 的功能以基于变量呈现组件的主要内容,如果未能解决你的问题,请参考以下文章

在 Reactjs 中实现嵌套路由的问题

尝试在 Reactjs 中实现一个简单的承诺

我想在 reactjs 中实现一个条件渲染系统

是否可以使用 IDP 独立代码在 ReactJS 中实现 open id connect SSO?

在reactjs功能组件中实现contextType的正确方法是什么?

如何通过 Interface Builder 在 Objective-C 中实现搜索栏