Forms and UI States

Back

Loading concept...

📱 User Interaction: Forms and UI States in React Native

🎭 The Magic Mailbox Story

Imagine you have a magic mailbox at home. This mailbox is special because:

  • It remembers everything you put inside it
  • It checks if your letters are written correctly
  • It tells you when something is wrong
  • It shows you when it’s busy sending your mail
  • It lets you know when there’s nothing inside

React Native forms work exactly like this magic mailbox! Let’s explore how.


📝 Form Handling

What is Form Handling?

Think of form handling like a teacher collecting homework papers. The teacher needs to:

  1. Collect each paper (get the input)
  2. Keep track of who gave what (store the data)
  3. Do something with all the papers (submit the form)

Simple Example:

import { useState } from 'react';
import {
  View, TextInput, Button, Text
} from 'react-native';

function SimpleForm() {
  const [name, setName] = useState('');

  const handleSubmit = () => {
    console.log('Hello, ' + name);
  };

  return (
    <View>
      <TextInput
        value={name}
        onChangeText={setName}
        placeholder="Your name"
      />
      <Button
        title="Say Hello"
        onPress={handleSubmit}
      />
    </View>
  );
}

What’s happening:

  • useState('') → Creates an empty box to store the name
  • onChangeText={setName} → Updates the box when you type
  • handleSubmit → Uses the stored name when you press the button

🎮 Controlled Components

What are Controlled Components?

Imagine a puppet on strings. You (the puppeteer) control every movement. The puppet doesn’t move on its own – it only moves when you tell it to.

Controlled components are inputs that React fully controls:

  • React holds the value
  • React updates the value
  • The input shows whatever React tells it to show
function ControlledInput() {
  const [email, setEmail] = useState('');

  return (
    <TextInput
      value={email}        // React says what to show
      onChangeText={setEmail}  // React updates when typed
      placeholder="Enter email"
      keyboardType="email-address"
    />
  );
}

Why Use Controlled Components?

graph TD A["User Types"] --> B["onChangeText fires"] B --> C["setEmail updates state"] C --> D["Component re-renders"] D --> E["TextInput shows new value"] E --> A

Benefits:

  • ✅ You always know what’s in the input
  • ✅ You can validate as the user types
  • ✅ You can transform input (like making text uppercase)
  • ✅ You have one source of truth

✅ Form Validation

What is Form Validation?

Remember our magic mailbox? Before sending a letter, it checks:

  • Is there a stamp? ✉️
  • Is the address written? 📍
  • Is everything spelled correctly? ✏️

That’s validation! Making sure the information is correct before using it.

Simple Validation Example:

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [errors, setErrors] = useState({});

  const validate = () => {
    const newErrors = {};

    // Check email
    if (!email.includes('@')) {
      newErrors.email = 'Need a real email!';
    }

    // Check password
    if (password.length < 6) {
      newErrors.password = 'Too short!';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = () => {
    if (validate()) {
      console.log('Form is good!');
    }
  };

  return (
    <View>
      <TextInput
        value={email}
        onChangeText={setEmail}
        placeholder="Email"
      />
      <TextInput
        value={password}
        onChangeText={setPassword}
        placeholder="Password"
        secureTextEntry
      />
      <Button
        title="Login"
        onPress={handleSubmit}
      />
    </View>
  );
}

Common Validation Rules

What to Check How to Check
Not empty value.length > 0
Valid email value.includes('@')
Min length value.length >= 6
Numbers only /^\d+$/.test(value)
Match fields password === confirmPassword

🚨 Error State Display

Showing Errors Nicely

When something’s wrong, we need to tell the user clearly – like a friend pointing out spinach in your teeth! 🥬

function FormWithErrors() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  const checkEmail = (text) => {
    setEmail(text);
    if (text && !text.includes('@')) {
      setError('Please enter a valid email');
    } else {
      setError('');
    }
  };

  return (
    <View>
      <TextInput
        value={email}
        onChangeText={checkEmail}
        placeholder="Email"
        style={{
          borderColor: error ? 'red' : 'gray',
          borderWidth: 1,
          padding: 10,
        }}
      />
      {error ? (
        <Text style={{ color: 'red' }}>
          ⚠️ {error}
        </Text>
      ) : null}
    </View>
  );
}

Error Display Flow

graph TD A["User Types"] --> B{Is Input Valid?} B -->|Yes| C["Clear Error"] B -->|No| D["Set Error Message"] C --> E["Normal Border"] D --> F["Red Border + Error Text"]

Best Practices:

  • 🔴 Use red color for errors
  • 📍 Show error near the problem field
  • 💬 Be helpful, not scary
  • ⏰ Show errors at the right time (not too early!)

⏳ Loading State UI

What is Loading State?

When you ask your phone to do something, sometimes it takes a moment. Like waiting for pizza to be delivered! 🍕

During this wait, we show a loading state so users know something is happening.

import { ActivityIndicator } from 'react-native';

function SubmitButton() {
  const [loading, setLoading] = useState(false);

  const handlePress = async () => {
    setLoading(true);

    // Pretend to send data (wait 2 seconds)
    await new Promise(r => setTimeout(r, 2000));

    setLoading(false);
  };

  return (
    <TouchableOpacity
      onPress={handlePress}
      disabled={loading}
      style={{
        backgroundColor: loading ? '#ccc' : 'blue',
        padding: 15,
        borderRadius: 8,
      }}
    >
      {loading ? (
        <ActivityIndicator color="white" />
      ) : (
        <Text style={{ color: 'white' }}>
          Submit
        </Text>
      )}
    </TouchableOpacity>
  );
}

Loading State Rules

Do ✅ Don’t ❌
Show spinner Leave blank screen
Disable buttons Let users tap again
Gray out form Pretend nothing’s happening
Keep user informed Make them guess

📭 Empty State UI

What is Empty State?

Imagine opening a toy box and finding it empty. Instead of just showing emptiness, you could put a note: “Your toys are waiting to be found! Go play outside! 🎈”

That’s empty state UI – making “nothing here” feel friendly and helpful.

function MessageList() {
  const [messages, setMessages] = useState([]);

  if (messages.length === 0) {
    return (
      <View style={styles.emptyContainer}>
        <Text style={styles.emoji}>📭</Text>
        <Text style={styles.title}>
          No Messages Yet
        </Text>
        <Text style={styles.subtitle}>
          When you receive messages,
          they'll appear here!
        </Text>
        <Button
          title="Invite Friends"
          onPress={() => {}}
        />
      </View>
    );
  }

  return (
    <FlatList
      data={messages}
      renderItem={({ item }) => (
        <Text>{item.text}</Text>
      )}
    />
  );
}

Great Empty States Include

graph TD A["Empty State"] --> B["Friendly Icon/Image"] A --> C["Clear Message"] A --> D["Helpful Action"] B --> E["📭 🎨 🌟"] C --> F["No items yet"] D --> G["Button to Add/Create"]

🎁 Putting It All Together

Here’s a complete form with ALL the states:

function CompleteForm() {
  const [name, setName] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const [submitted, setSubmitted] = useState(false);

  const validate = () => {
    if (name.length < 2) {
      setError('Name is too short');
      return false;
    }
    setError('');
    return true;
  };

  const handleSubmit = async () => {
    if (!validate()) return;

    setLoading(true);
    await new Promise(r => setTimeout(r, 1500));
    setLoading(false);
    setSubmitted(true);
  };

  // Success state (after submit)
  if (submitted) {
    return (
      <View style={styles.success}>
        <Text>✅ Thank you, {name}!</Text>
      </View>
    );
  }

  return (
    <View>
      {/* Input with error state */}
      <TextInput
        value={name}
        onChangeText={setName}
        placeholder="Your name"
        style={{
          borderColor: error ? 'red' : '#ddd',
          borderWidth: 1,
          padding: 12,
        }}
      />

      {/* Error display */}
      {error ? (
        <Text style={{ color: 'red' }}>
          {error}
        </Text>
      ) : null}

      {/* Button with loading state */}
      <TouchableOpacity
        onPress={handleSubmit}
        disabled={loading}
      >
        {loading ? (
          <ActivityIndicator />
        ) : (
          <Text>Submit</Text>
        )}
      </TouchableOpacity>
    </View>
  );
}

🌟 Quick Summary

Concept What It Does Like…
Form Handling Collects & manages input Teacher collecting papers
Controlled Components React controls input value Puppet on strings
Form Validation Checks if data is correct Spell checker
Error State Shows what’s wrong Helpful friend
Loading State Shows “please wait” Pizza delivery tracker
Empty State Friendly “nothing here” Decorated empty box

🚀 You Did It!

Now you understand how React Native forms work:

  1. Collect information with controlled components
  2. Validate to make sure it’s correct
  3. Show errors when something’s wrong
  4. Display loading while waiting
  5. Handle empty states gracefully

Forms are like magic mailboxes – they collect, check, wait, and communicate. And now you know how to build them! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.