Как инженеру-программисту Reactjs перейти на Swift и SwiftUI

Инженер-программист ReactJS может плавно перейти на изучение Swift и SwiftUI. Для этого нужно найти соответствия знакомых концепций в новой среде разработки. В данном руководстве мы рассмотрим аналоги распространенных шаблонов ReactJS в Swift и SwiftUI.

Примечание. Есть масса способов решить задачу. В данном случае примеры в виде небольших фрагментов кода иллюстрируют общие концепции. 

Для дальнейших экспериментов и работы с примерами рекомендую скачать Playground с GitHub. 

Инициализация проекта 

Начать новый проект React можно разными способами. Один из них  —  использовать create-react-app:

npx create-react-app my-app
cd my-app
npm start

В Swift для создания нового проекта SwiftUI применяется Xcode

  1. Открываем Xcode
  2. Выбираем Create a new Xcode project (“Создать новый проект Xcode”). 
  3. Сначала выбираем iOS (или macOS, или Multiplatform), затем App и далее SwiftUI в качестве опции interface.

Структурирование компонентов 

Компоненты  —  это строительные блоки UI приложения. 

В React компоненты часто представляют из себя функции, которые возвращают JSX:

const Greeting = () => <h1>Hello, world!</h1>;

В SwiftUI компоненты называются представлениями (англ. View). Их определяют как структуры, соответствующие протоколу View:

struct Greeting: View {
var body: some View {
Text("Hello, world!")
}
}

Получение входных данных формы 

Как правило, любое приложение выполняет обработку пользовательского ввода. 

ReactJS

В React вы создаете поле для ввода и с помощью хука useState отслеживаете его значения: 

const InputComponent = () => {
const [inputValue, setInputValue] = useState("");

const handleChange = event => setInputValue(event.target.value);

return <input type="text" value={inputValue} onChange={handleChange} />;
};

SwiftUI

SwiftUI упрощает данный процесс. С помощью обертки свойства @State и привязки ее к вводу он выполняет синхронизацию:  

struct InputView: View {
@State private var inputValue = ""

var body: some View {
TextField("Enter text", text: $inputValue)
.padding()
}
}

Использование состояния 

Состояние имеет важное значение для реактивных пользовательских интерфейсов. 

ReactJS

В React для управления состоянием компонентов часто задействуется хук useState:

const Counter = () => {
const [count, setCount] = useState(0);

return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
};

SwiftUI

Аналогичным образом в SwiftUI применяется обертка свойства @State для отслеживания локального состояния представления: 

struct CounterView: View {
@State private var count = 0

var body: some View {
Button("Clicked \(count) times") {
count += 1
}
.padding()
}
}

Передача обратных вызовов дочерним компонентам

Передача функций в качестве входных параметров (англ. props)  —  обычная практика в процессе взаимодействия родительских и дочерних компонентов. 

ReactJS

В React через входные параметры вы передаете функцию дочернему компоненту, который ее вызывает: 

const Parent = () => {
const handleAction = () => console.log("Action handled");

return <Child onAction={handleAction} />;
};

const Child = ({ onAction }) => <button onClick={onAction}>Do Action</button>;

SwiftUI

В SwiftUI этот процесс осуществляется путем передачи замыканий дочерним представлениям:

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

Совместное использование данных в приложении

Зачастую работа приложения требует обмена данными между различными компонентами. 

ReactJS (с Context)

React предоставляет инструмент Context API, широко применяемый для совместного использования состояния и передачи его через дерево компонентов. Он избавляет от необходимости передавать входные параметры вручную: 

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 (с EnvironmentObject)

В свою очередь SwiftUI предлагает EnvironmentObject, позволяющий представлениям совместно использовать общий источник данных: 

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

Обработка побочных эффектов 

Реагирование на изменения  —  важнейшая характеристика работы любого современного UI-фреймворка.

ReactJS (с useEffect)

В React хук useEffect позволяет выполнять действия, называемые побочными эффектами, в функциональных компонентах: 

const MyComponent = () => {
useEffect(() => {
console.log("Component mounted");

return () => console.log("Component unmounted");
}, []);

return <div>Hello, World!</div>;
};

SwiftUI (с onAppear и onDisappear)

SwiftUI предоставляет модификаторы onAppear и onDisappear, которые можно добавлять к представлениям для обеспечения аналогичной функциональности: 

struct MyView: View {
var body: some View {
Text("Hello, World!")
.onAppear {
print("View appeared")
}
.onDisappear {
print("View disappeared")
}
}
}

Примечание. Модификатор .task более подходит для вызова асинхронных функций async при первом отображении представления, чем .onAppear. Если представление ликвидируется до завершения задачи, то задача автоматически отменяется. 

Маршрутизация и навигация 

Навигация  —  это основа любого приложения. 

ReactJS (с React Router)

В React для навигации применяется React Router

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 предлагает NavigationView и NavigationLink для создания навигационных интерфейсов: 

struct NavigationExampleView: View {
var body: some View {
NavigationView {
NavigationLink(destination: HomeView()) {
Text("Home")
}
}
}
}

Заключение 

SwiftUI предполагает декларативный подход к созданию UI, аналогичный ReactJS, но более тесно интегрированный с Swift.

Установив соответствия между ReactJS и SwiftUI, вы сможете легко перейти с одного инструмента на другой. Конечно, потребуется время для освоения новых знаний, но понимание сходств и различий в шаблонах сделает процесс обучения более плавным. 

SwiftUI очень быстро развивается, поэтому целесообразно отслеживать новейшие изменения и функциональности. 

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Drew Althage: A Few Code Examples for Reactjs Engineers Learning Swift and SwiftUI

Предыдущая статьяВведение в Page Visibility API
Следующая статья6 способов оптимизировать рабочий процесс в Pandas