In our core UiProps documentation, the pattern of composing multiple props mixins into a single component props API is introduced.
This example builds on that, showing a lightweight example a common use-case for such composition.
We'll show three components
- A
Foocomponent that has its own props API - and default rendering behavior when rendered standalone. - A
FooBarcomponent that has its own props API, in addition to theFooprops API. This allows consumers to set props declared inFooPropsMixin, which will be forwarded to theFoocomponent it renders. - A
FooBazcomponent, the functional version ofFooBar.
import 'package:over_react/over_react.dart';
part 'foo.over_react.g.dart';
UiFactory<FooPropsMixin> Foo =
castUiFactory(_$Foo); // ignore: undefined_identifier
mixin FooPropsMixin on UiProps {
Set<int> qux;
}
class FooComponent extends UiComponent2<FooPropsMixin> {
@override
get defaultProps => (newProps()
..qux = {1, 2, 3}
);
@override
render() {
return (Dom.div()
..modifyProps(addUnconsumedDomProps)
..className = (forwardingClassNameBuilder()..add('foo'))
)(
'Qux: ',
props.qux.map((n) => n),
props.children,
);
}
}Which, when rendered on its own - produces the following HTML:
<div class="foo">Qux: 123</div>To compose the Foo component using FooBar, we'll expose the prop API for both the FooPropsMixin and the BarPropsMixin like so:
import 'package:over_react/over_react.dart';
import 'foo.dart';
part 'foo_bar.over_react.g.dart';
UiFactory<FooBarProps> FooBar =
castUiFactory(_$FooBar); // ignore: undefined_identifier
mixin BarPropsMixin on UiProps {
bool baz;
Set<String> bizzles;
}
class FooBarProps = UiProps with BarPropsMixin, FooPropsMixin;
class FooBarComponent extends UiComponent2<FooBarProps> {
// Only consume the props found within BarPropsMixin, so that any prop values
// found in FooPropsMixin get forwarded to the child Foo component via `addUnconsumedProps`.
@override
get consumedProps => propsMeta.forMixins({BarPropsMixin});
@override
render() {
return (Foo()
..modifyProps(addUnconsumedProps)
..className = (forwardingClassNameBuilder()..add('foo__bar'))
)(
(Dom.div()..className = 'foo__bar__bizzles')(
'Bizzles: ',
Dom.ol()(
props.bizzles.map(_renderBizzleItem).toList(),
),
),
);
}
ReactElement _renderBizzleItem(String bizzle) {
return (Dom.li()..key = bizzle)(bizzle);
}
}Which, when composed / rendered like so:
import 'dart:html';
import 'package:over_react/react_dom.dart' as react_dom;
import 'package:over_react/over_react.dart';
// An example of where the `FooBar` component might be exported from
import 'package:my_package_name/foobar.dart';
@override
main() {
final abcFooBar = (FooBar()
..className = 'foo_bar--abc'
..aria.label = 'I am FooBar!'
..qux = {2, 3, 4}
..bizzles = {'a', 'b', 'c'}
)();
react_dom.render(abcFooBar, querySelector('#some_element_id'));
}Produces the following HTML:
<div class="foo foo__bar foo__bar--abc">
Qux: 234
<div class="foo__bar__bizzles">
Bizzles:
<ol>
<li>a</li>
<li>b</li>
<li>c</li>
</ol>
</div>
</div>To compose the Foo component using FooBaz, a functional component, we'll expose the prop API for both the FooPropsMixin and the BazPropsMixin like so:
import 'package:over_react/over_react.dart';
import 'foo.dart';
part 'foo_baz.over_react.g.dart';
mixin BarPropsMixin on UiProps {
bool baz;
Set<String> bizzles;
}
class FooBazProps = UiProps with BarPropsMixin, FooPropsMixin;
UiFactory<FooBazProps> FooBaz = uiFunction(
(props) {
return (Foo()
// Only forward the props not belonging to BarPropsMixin to the child Foo component.
..addAll(props.getPropsToForward(exclude: {BarPropsMixin}))
..className = (forwardingClassNameBuilder()..add('foo__baz'))
)(
(Dom.div()..className = 'foo__baz__bizzles')(
'Bizzles: ',
Dom.ol()(
props.bizzles.map(_renderBizzleItem).toList(),
),
),
);
ReactElement _renderBizzleItem(String bizzle) {
return (Dom.li()..key = bizzle)(bizzle);
}
},
_$FooBazConfig, // ignore: undefined_identifier
);Which, when composed / rendered like so:
import 'dart:html';
import 'package:over_react/react_dom.dart' as react_dom;
import 'package:over_react/over_react.dart';
// An example of where the `FooBaz` component might be exported from
import 'package:my_package_name/foobaz.dart';
@override
main() {
final abcFooBaz = (FooBaz()
..className = 'foo_baz--abc'
..aria.label = 'I am FooBaz!'
..qux = {2, 3, 4}
..bizzles = {'a', 'b', 'c'}
)();
react_dom.render(abcFooBaz, querySelector('#some_element_id'));
}Produces the following HTML:
<div class="foo foo__baz foo__baz--abc">
Qux: 234
<div class="foo__baz__bizzles">
Bizzles:
<ol>
<li>a</li>
<li>b</li>
<li>c</li>
</ol>
</div>
</div>To learn more about the
consumedPropsbehavior shown above, check out the mixin-based prop forwarding documentation.