Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8892688

Browse files
committed
feat: add function builders explanation
1 parent 46f3b77 commit 8892688

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

‎README.rst‎

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,54 @@ In SwiftUI:
7575
7676
Almost the same in semantic!
7777

78+
Conditional & List
79+
------------------
80+
Structure of the contents can be dynamic, the most common patterns are conditional
81+
and list.
82+
83+
In React:
84+
85+
.. code-block:: javascript
86+
87+
const UserList = ({ users }) => {
88+
if (!users.length) {
89+
return <p>No users</p>;
90+
}
91+
92+
return (
93+
<ul>
94+
{users.map(e => (
95+
<li key={e.id}>{e.username}</li>
96+
))}
97+
</ul>
98+
);
99+
}
100+
101+
In SwiftUI:
102+
103+
.. code-block:: swift
104+
105+
struct UserList: View {
106+
let users: [User]
107+
108+
var body: some View {
109+
Group {
110+
if users.isEmpty {
111+
Text("No users")
112+
} else {
113+
VStack {
114+
ForEach(users, id: \.id) {
115+
Text("\(0ドル.username)")
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
SwiftUI has built-in ``ForEach`` element, you don't need to manually map the data
124+
array to views, so you can have a much neater code.
125+
78126
Events Handling
79127
---------------
80128
In React:
@@ -580,7 +628,107 @@ struct, pretty like how **Hook** works in React.
580628
In this way, even though the ``View`` objects are recreated frequently, as long as
581629
the view is not unmounted, the state will be kept.
582630

631+
How function builders works?
632+
----------------------------
633+
As we mention earlier, SwiftUI use **Function Builders** as DSL to let us build
634+
contents. There is also a draft proposal about it: `Function builders (draft proposal)`_.
635+
636+
Let's first take a look at how JSX is transpiled to JavaScript. We have this:
637+
638+
.. code-block:: javascript
639+
640+
const UserInfo = ({ users }) => {
641+
if (!users.length) {
642+
return <p>No users</p>;
643+
}
644+
645+
return (
646+
<div>
647+
<p>Great!</p>
648+
<p>We have {users.length} users!</p>
649+
</div>
650+
);
651+
}
652+
653+
And this is the output from Babel with ``react`` preset:
654+
655+
.. code-block:: javascript
656+
657+
const UserInfo = ({
658+
users
659+
}) => {
660+
if (!users.length) {
661+
return /*#__PURE__*/React.createElement("p", null, "No users");
662+
}
663+
664+
return /*#__PURE__*/React.createElement("div", null,
665+
/*#__PURE__*/React.createElement("p", null, "Great!"),
666+
/*#__PURE__*/React.createElement("p", null, "We have ", users.length, " users!")
667+
);
668+
};
669+
670+
Most of the structure is identical, and the HTML tags are transformed to ``React.createElement``
671+
calls. That makes sense, the function doesn't produce component instances, instead,
672+
it produces elements. Elements describe how to configure components or DOM elements.
673+
674+
Now, let's back to SwiftUI. There is the same example:
675+
676+
.. code-block:: swift
677+
678+
struct UserInfo: View {
679+
let users: [User]
680+
681+
var body: some View {
682+
Group {
683+
if users.isEmpty {
684+
Text("No users")
685+
} else {
686+
VStack {
687+
Text("Great!")
688+
Text("We have \(users.count) users!")
689+
}
690+
}
691+
}
692+
}
693+
}
694+
695+
And this is the actual code represented by it:
696+
697+
.. code-block:: swift
698+
699+
struct UserInfo: View {
700+
let users: [User]
701+
702+
var body: some View {
703+
let v: _ConditionalContent<Text, VStack<TupleView<(Text, Text)>>>
704+
if users.isEmpty {
705+
v = ViewBuilder.buildEither(first: Text("No users"))
706+
} else {
707+
v = ViewBuilder.buildEither(second: VStack {
708+
return ViewBuilder.buildBlock(
709+
Text("Great!"),
710+
Text("We have \(users.count) users!")
711+
)
712+
})
713+
}
714+
return v
715+
}
716+
}
717+
718+
Voila! All the dynamic structures are replaced by ``ViewBuilder`` method calls. In
719+
this way, we can use a complex type to represent the structure. Like ``if``
720+
statement will be transformed to ``ViewBuilder.buildEither`` call, and its return
721+
value contains the information of both ``if`` block and ``else`` block.
722+
723+
``ViewBuilder.buildBlock`` is used to represent a child element that contains
724+
multiple views.
725+
726+
With function builders, you can even create your own DSLs. And this year in WWDC20,
727+
Apple released more features based on function builders, like **WidgetKit** and
728+
SwiftUI **App Structure**.
729+
583730
.. References:
584731
585732
.. _`Thinking in React Hooks`: https://wattenberger.com/blog/react-hooks
586733
.. _`[SE-0258] Property Wrappers`: https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md
734+
.. _`Function builders (draft proposal)`: https://github.com/apple/swift-evolution/blob/9992cf3c11c2d5e0ea20bee98657d93902d5b174/proposals/XXXX-function-builders.md

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /