在 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 的功能以基于变量呈现组件的主要内容,如果未能解决你的问题,请参考以下文章
是否可以使用 IDP 独立代码在 ReactJS 中实现 open id connect SSO?