demo-react-native-app: Week #1

Three days. From nothing to a React Native mobile app installed on my phone.

The project itself is deliberately simple—a text input that echoes whatever you type when you press a button. The kind of trivial app that lets me focus on React Native mechanics and mobile development workflow instead of complex application logic. Beyond just learning React Native, I wanted to use Expo’s managed workflow to see how much of the native toolchain complexity could be abstracted away. Even if it feels a bit like cheating.

## Monday: Project Setup

Monday was about getting the development environment configured. Ran `npx create-expo-app@latest` and watched it scaffold the entire project structure—TypeScript configuration, Expo Router setup, example components, dependencies. The whole thing took maybe five minutes.

Using Expo feels like cheating, honestly. With bare React Native, I’d be dealing with Android Studio, Xcode, Gradle configurations, SDK management, and all the native build toolchain setup. Expo abstracts all of that away. But I decided to live with it for now—I’m learning React Native concepts, not Android/iOS build systems. The choice is similar to using React instead of vanilla JavaScript, or Express instead of raw Node.js. You build on good abstractions.

The initial project structure was interesting. Expo uses file-based routing with their Router library, so the `app/` directory determines navigation. The `(tabs)` folder creates tab navigation automatically. Convention over configuration. I’d be setting this up manually in bare React Native.

## Tuesday: Building the UI

Tuesday I focused on the actual application code. The goal was simple: text input, button, display output. But the way you build UI in React Native is fundamentally different from web development, even though you’re using React.

Started by gutting the example code in `app/(tabs)/index.tsx` and building from scratch. The first surprise: you can’t just write text directly. Every bit of text must be wrapped in a `<Text>` component. This isn’t HTML. There’s no DOM. `<View>` replaces `<div>`, `<Text>` replaces `<span>` or `<p>`, `<TextInput>` replaces `<input>`. These aren’t web elements—they compile to actual native components. On Android, `<View>` becomes `android.view.View`. On iOS, it’s `UIView`.

The second surprise: controlled components work differently than I expected. In traditional web development, you’d grab a reference to the input element and read its value directly. React Native is entirely state-driven. The `<TextInput>` component has a `value` prop connected to state and an `onChangeText` callback that updates state. State is the single source of truth. The UI automatically reflects state changes. No querying the DOM, because there is no DOM to query.

Added `useState` hooks for `inputValue` and `displayText`:

“`tsx

const [inputValue, setInputValue] = useState(”);

const [displayText, setDisplayText] = useState(”);

“`

The pattern is declarative: user types, `onChangeText` fires, state updates, component re-renders, UI updates. Every keystroke triggers a re-render, but React Native optimizes this internally.

Styling came next. React Native uses `StyleSheet.create()` instead of CSS. All properties are camelCase (`backgroundColor`, not `background-color`), no units are needed (just numbers representing density-independent pixels), and everything is flexbox by default. The default flex direction is `column`, which is opposite of web’s default `row`. This tripped me up initially—items stack vertically unless you explicitly set `flexDirection: ‘row’`.

## Thursday: Building and Deploying

Thursday was about getting the app off my development machine and onto my phone. This is where mobile development complexity becomes apparent.

Installed EAS CLI globally (`npm install -g eas-cli`), logged in (`eas login`), and ran `eas build:configure`. This created an `eas.json` configuration file with build profiles—development, preview, production. Each profile has different settings. Preview builds create APK files (directly installable), production builds create AAB files (for Play Store submission).

Ran the build command: `eas build –platform android –profile preview`. The process took about 15 minutes. My code gets uploaded to Expo’s servers, they create a build environment, install dependencies, compile the native code, sign the APK, and upload it to a CDN. I get a download link valid for 30 days.

It’s a lot of work to get compiled software running on “what effectively is a computer but happens to be a mobile phone.” Web development is simpler: write code, save, refresh browser. Mobile requires bundling, cross-compiling (x86 to ARM architecture), signing, packaging, transferring to a different device, and installing in a sandboxed environment. Expo makes this dramatically easier than it would be otherwise—without EAS Build, I’d need the full Android SDK, Android Studio, Gradle setup, and manual signing key management.

Downloaded the APK to my phone and tapped to install. Android immediately flagged it with a Play Protect warning. The app isn’t from the Play Store, isn’t signed by a recognized developer, and Play Protect doesn’t recognize it. Normal for development apps. Tapped “Install anyway,” and the app installed.

Launched the app. It opened in standalone mode—no Expo Go required, no development server connection. Just a regular Android app. Typed text into the input, pressed the button, saw the output update. Simple, but it works. The app I wrote is now running natively on my phone.

## React Native vs Web

The biggest conceptual shift is the lack of DOM access. In web development, even with React, you can still grab elements with refs and manipulate them directly if needed. React Native has no DOM. Everything is state-driven and declarative.

The components themselves are different. `<View>` and `<Text>` aren’t HTML elements rendered in a web view—they’re native UI components. The React Native bridge translates your JavaScript code into native API calls. When you render a `<Text>` component, the native side creates an actual `TextView` on Android or `UITextView` on iOS. This is fundamentally different from frameworks like Cordova or Ionic that wrap web content in a native shell. React Native apps are truly native.

This has implications for performance. Native components are fast—they’re the same components you’d use writing Java/Kotlin or Swift code directly. But the bridge introduces overhead. Every state update, every UI change crosses the bridge from JavaScript to native. For this simple app, the overhead is negligible. For complex apps with heavy interactions, it becomes a consideration. React Native’s architecture is evolving to address this (the new architecture uses JSI to eliminate the bridge), but that’s not something I need to worry about for a text echo app.

The styling differences are practical. CSS has thousands of properties accumulated over decades. React Native’s StyleSheet API has a curated subset—enough to build mobile UIs, but not the full power (or complexity) of CSS. You can’t use pseudo-classes like `:hover` (no mouse on mobile), can’t use media queries the same way (screen sizes are handled differently), and have to think about flexbox layout more explicitly.

## State Management in React Native

React hooks work the same in React Native as in React for web, but the usage patterns feel different because of controlled components.

The `useState` hook returns an array: `[currentValue, setterFunction]`. Destructuring makes it readable:

“`tsx

const [inputValue, setInputValue] = useState(”);

“`

React creates the setter function for me. When I call `setInputValue(newValue)`, React updates the internal state, marks the component as needing a re-render, and schedules the update. The component function runs again, this time with `inputValue` containing the new value, and React updates the UI to match the new JSX.

Controlled components in React Native feel more explicit than on web. The `<TextInput>` component requires both `value` and `onChangeText` props to be fully controlled. The flow is: user types → `onChangeText` fires → state updates → component re-renders → `<TextInput value={…}>` renders with new value. The input’s displayed value always comes from state, never from the DOM (because there is no DOM).

This pattern makes validation and transformation easy. Want to limit input to 10 characters? Check length in `onChangeText` before calling the setter. Want to force uppercase? Transform the text before updating state. The input will automatically reflect these constraints because it’s controlled.

## Mobile Development Complexity

The thought that kept coming back: “It seems like a lot of work to just get compiled software running on what effectively is a computer but happens to be a mobile phone.”

And it’s true. Mobile development has inherent complexity that web development doesn’t:

**Architecture differences**: My laptop is x86_64. My phone is ARM. Cross-compilation is required. The JavaScript runs on the same architecture (interpreted by the JavaScript engine), but the native components have to be compiled for ARM.

**Platform restrictions**: Mobile OSes are sandboxed. Apps can’t access arbitrary files, can’t run background processes indefinitely, require permissions for sensitive APIs. Security is tighter than desktop.

**Distribution complexity**: On the web, deployment is simple—upload files to a server, users access via browser. On mobile, there’s an entire packaging and signing process. Apps must be signed with cryptographic keys. Installation requires system-level permissions. Update mechanisms are different.

**Multiple versions**: Web apps run the version you deploy. Mobile apps run whatever version the user installed and may never update. You have to support multiple versions simultaneously. API compatibility matters more.

But also: once the tooling is set up, the workflow isn’t bad. Expo hides most of the complexity. For bare React Native, it’s worse—but still manageable compared to pure native development. And the tradeoff is worth it: one codebase, two platforms (iOS and Android). Write once, deploy everywhere.

**Project**: demo-react-native-app

**Week**: Week #1

**Commits**: 10

**Status**: Phase 1 complete—built, deployed, installed on device

**Lines added**: ~3,400 (including extensive learning plan and Phase 1 notes)


Publicado

em

por

Etiquetas:

Comentários

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *