簡體   English   中英

在 reactjs 中實現基於 INTERFACE 的功能,以基於變量渲染組件

[英]Implement INTERFACE based functionality in reactjs to render component based on variable

如何使用基於界面的功能來基於選項卡選擇呈現組件。

假設我有 3 個組件,即

  1. OneTimeOnlySchedule 組件
  2. DailySchedule 組件
  3. 每周計划組件

我想要某種功能,其中所有這些組件都實現接口InterfaceBasedComponent

例如

  1. OneTimeOnlyScheduleComponent implements InterfaceBasedComponent
  2. DailyScheduleComponent implements InterfaceBasedComponent
  3. WeeklyScheduleComponent implements InterfaceBasedComponent

在 ReactJS 中,我應該能夠使用工廠模式或其他方式創建 object。

GitHub 代碼托管 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>

理想情況下,我希望簡化代碼以使用基於接口的 object 渲染,例如InterfaceBasedComponent 該接口應該能夠創建所需組件的 object。

<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 >

你說:

我應該能夠使用工廠模式創建 object... 我希望簡化代碼以使用基於接口的 object 渲染

但是您實際上想要簡化什么? (例如,工廠不是接口)。

接口

如果您明確想要使用接口,那么這是不可能的,因為 Javascript 沒有接口,因此沒有 React。

Typscript 中有接口,但我確定這不是你的意思)

工廠

但是您可以很好地使用工廠 function 來創建組件:

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 中還有高階組件(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 的意圖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM