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

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

假设我有 3 个组件,即

  1. OneTimeOnlyScheduleComponent
  2. DailyScheduleComponent
  3. WeeklyScheduleComponent

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

例如

  1. OneTimeOnlyScheduleComponent implements InterfaceBasedComponent
  2. DailyScheduleComponent implements InterfaceBasedComponent
  3. 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 >

【问题讨论】:

标签: javascript reactjs oop ecmascript-6 javascript-objects


【解决方案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 的意图。

【讨论】:

    猜你喜欢
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-02
    • 2020-05-17
    • 1970-01-01
    • 2021-11-12
    • 2020-12-19
    相关资源
    最近更新 更多