As a software engineer familiar with ReactJS, learning Swift and SwiftUI can be a smooth transition if you can map the concepts you are familiar with to the new environment. In this guide, we will look at how common ReactJS patterns translate into Swift and SwiftUI.
Please note — There are a million different ways to skin a cat. The following examples are intended to be short code snippets to highlight general concepts.
Initializing a Project
There are many ways of starting a new React project; one method is using create-react-app:
npx create-react-app my-app
cd my-app
npm start
In Swift, you use Xcode to create a new SwiftUI project:
- Open Xcode
- Select “Create a new Xcode project”
- With iOS (or macOS or Multiplatform) selected, choose “App” and select SwiftUI for the “interface” option.
Structuring Components
Components are the building blocks of your application’s UI.
In React, components are often functions that return some JSX.
const Greeting = () => <h1>Hello, world!</h1>;
In SwiftUI, components are called Views. You define them as structures that conform to the View protocol.
struct Greeting: View {
var body: some View {
Text("Hello, world!")
}
}
Capturing Form Inputs
Handling user inputs is a common pattern in any application.
ReactJS:
In React, you might create an input field and use the useState hook to keep track of its value.
const InputComponent = () => {
const [inputValue, setInputValue] = useState("");
const handleChange = event => setInputValue(event.target.value);
return <input type="text" value={inputValue} onChange={handleChange} />;
};
SwiftUI:
SwiftUI streamlines this process. By using the @State property wrapper and binding it to an input, SwiftUI handles the synchronization for you.
struct InputView: View {
@State private var inputValue = ""
var body: some View {
TextField("Enter text", text: $inputValue)
.padding()
}
}
Using State
State is essential for reactive user interfaces.
ReactJS:
In React, we often use the useState hook to manage component-level state.
const Counter = () => {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
};
SwiftUI:
Similarly, in SwiftUI, we use the @State property wrapper to keep track of the local state in a view.
struct CounterView: View {
@State private var count = 0
var body: some View {
Button("Clicked (count) times") {
count += 1
}
.padding()
}
}
Passing Callbacks to Child Components
Passing functions as props is common for parent-child communication.
ReactJS:
In React, you can pass a function to a child component via props that the child can call.
const Parent = () => {
const handleAction = () => console.log("Action handled");
return <Child onAction={handleAction} />;
};
const Child = ({ onAction }) => <button onClick={onAction}>Do Action</button>;
SwiftUI:
The same can be achieved in SwiftUI by passing closures to child views.
struct ParentView: View {
var body: some View {
ChildView(onAction: { print("Action handled") })
}
}
struct ChildView: View {
let onAction: () -> Void
var body: some View {
Button("Do Action", action: onAction)
}
}
Sharing Data Across the App
Applications often require sharing data among various components.
ReactJS (using Context):
In React, the Context API is a popular choice for sharing state and passing it deep into the component tree without manually passing props.
const AppContext = createContext();
const Parent = () => (
<AppContext.Provider value={{ message: "Hello from context" }}>
<Child />
</AppContext.Provider>
);
const Child = () => {
const context = useContext(AppContext);
return <div>{context.message}</div>;
};
SwiftUI (using EnvironmentObject):
SwiftUI offers EnvironmentObject, allowing views to share a common data source.
class AppData: ObservableObject {
@Published var message = "Hello from environment object"
}
struct ParentView: View {
var body: some View {
ChildView().environmentObject(AppData())
}
}
struct ChildView: View {
@EnvironmentObject var appData: AppData
var body: some View {
Text(appData.message)
}
}
Handling Side Effects
Reacting to changes is crucial for any modern UI Framework.
ReactJS (using useEffect):
In React, the useEffect hook allows you to perform side effects in function components.
const MyComponent = () => {
useEffect(() => {
console.log("Component mounted");
return () => console.log("Component unmounted");
}, []);
return <div>Hello, World!</div>;
};
SwiftUI (using onAppear and onDisappear):
SwiftUI provides onAppear and onDisappear modifiers that can be attached to views for similar functionality.
struct MyView: View {
var body: some View {
Text("Hello, World!")
.onAppear {
print("View appeared")
}
.onDisappear {
print("View disappeared")
}
}
}
Side note, using the .task modifier may be preferable to .onAppear for invoking async functions when a view first renders. If the view has been destroyed before the task completes, the task will automatically be canceled.
Routing and Navigation
Navigation is the backbone of any application.
ReactJS (using React Router):
In React, React Router is commonly used for navigation.
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const Navigation = () => (
<Router>
<div>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
</ul>
</nav>
<Route path="/" exact component={Home} />
</div>
</Router>
);
SwiftUI (using NavigationView and NavigationLink):
SwiftUI provides NavigationView and NavigationLink for creating navigational interfaces.
struct NavigationExampleView: View {
var body: some View {
NavigationView {
NavigationLink(destination: HomeView()) {
Text("Home")
}
}
}
}
Conclusion
SwiftUI brings a declarative way of building UI similar to ReactJS but more tightly integrated with Swift.
Understanding these mappings between ReactJS and SwiftUI can make transitioning between the two more intuitive. While a learning curve is involved, understanding the similarities and differences in patterns can make the process smoother.
Remember that SwiftUI is evolving rapidly, so stay updated with the latest changes and features.
When you’re ready to move onto HTTP requests and hook up your app to a remote API, check out “Transitioning From JavaScript to Swift and SwiftUI? Start With This Simple Networking Layer”
A Few Code Examples for Reactjs Engineers Learning Swift and SwiftUI was originally published in Better Programming on Medium, where people are continuing the conversation by highlighting and responding to this story.