React Dasar

Components & Props

Membuat komponen React dan menggunakan props untuk komunikasi antar komponen

Apa itu Component?

Component adalah blok pembangun utama aplikasi React. Component memungkinkan Kalian membagi UI menjadi bagian-bagian yang independen, reusable, dan mudah dikelola.

Functional vs Class Components

React memiliki dua jenis komponen: Class Components dan Functional Components. Dalam praktikum ini, kita akan fokus pada Functional Components dengan Hooks, yang merupakan pendekatan modern dan direkomendasikan.

Membuat Component Pertama

Component Header

Mari membuat komponen Header yang sederhana:

src/components/Header/Header.jsx
import React from 'react';
import './Header.css';

function Header({ title, description }) {
  return (
    <header className="header">
      <h1>{title}</h1>
      {description && <p>{description}</p>}
    </header>
  );
}

export default Header;
src/components/Header/Header.css
.header {
  background-color: #3498db;
  color: white;
  padding: 1rem;
  text-align: center;
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.header h1 {
  margin: 0;
  font-size: 1.8rem;
}

.header p {
  margin: 0.5rem 0 0;
  font-size: 1rem;
  opacity: 0.9;
}

Menggunakan Component

Sekarang kita bisa menggunakan component Header di App.jsx:

src/App.jsx
import React from 'react';
import Header from './components/Header/Header';
import './App.css';

function App() {
  return (
    <div className="App">
      <Header
        title="React Task Manager"
        description="Kelola tugas Anda dengan mudah"
      />
    </div>
  );
}

export default App;

Props - Komunikasi Antar Component

Props (properties) adalah cara untuk mengirim data dari parent component ke child component. Props bersifat read-only dan tidak boleh diubah oleh child component.

Jenis-jenis Props

// Mengirim string sebagai props
<Header title="My App" description="Welcome!" />

// Di dalam component
function Header({ title, description }) {
  return <h1>{title}</h1>
}
// Mengirim number sebagai props
<Counter initialCount={0} step={1} />

// Di dalam component
function Counter({ initialCount, step }) {
  return <div>Start: {initialCount}</div>
}
// Mengirim boolean sebagai props
<Button disabled={true} loading={false} />

// Di dalam component
function Button({ disabled, loading }) {
  return (
    <button disabled={disabled}>
      {loading ? 'Loading...' : 'Submit'}
    </button>
  )
}
// Mengirim function sebagai props
<Button onClick={() => alert('Clicked!')} />

// Di dalam component
function Button({ onClick }) {
  return <button onClick={onClick}>Click Me</button>
}
// Mengirim object sebagai props
<UserCard user={{ name: 'John', age: 30 }} />

// Di dalam component
function UserCard({ user }) {
  return <div>{user.name} - {user.age}</div>
}

Membuat Component Task Manager

Mari membuat beberapa komponen untuk aplikasi Task Manager:

Component TaskItem

src/components/TaskItem/TaskItem.jsx
import React from 'react';
import './TaskItem.css';

function TaskItem({ task, onDelete, onToggleComplete }) {
  return (
    <div className={`task-item ${task.completed ? 'completed' : ''}`}>
      <div className="task-content">
        <input
          type="checkbox"
          checked={task.completed}
          onChange={() => onToggleComplete(task.id)}
        />
        <span className="task-title">{task.title}</span>
      </div>
      <div className="task-actions">
        <button
          className="delete-btn"
          onClick={() => onDelete(task.id)}
        >
          Delete
        </button>
      </div>
    </div>
  );
}

export default TaskItem;
src/components/TaskItem/TaskItem.css
.task-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  margin-bottom: 0.5rem;
  background-color: #f8f9fa;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  transition: all 0.3s ease;
}

.task-item.completed {
  background-color: #e9ecef;
  opacity: 0.7;
}

.task-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.task-title {
  font-size: 1rem;
}

.completed .task-title {
  text-decoration: line-through;
  color: #6c757d;
}

.delete-btn {
  background-color: #dc3545;
  color: white;
  border: none;
  border-radius: 4px;
  padding: 0.25rem 0.5rem;
  cursor: pointer;
  transition: background-color 0.2s;
}

.delete-btn:hover {
  background-color: #c82333;
}

Component TaskForm

src/components/TaskForm/TaskForm.jsx
import React, { useState } from 'react';
import './TaskForm.css';

function TaskForm({ onAddTask }) {
  const [title, setTitle] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!title.trim()) return;

    const newTask = {
      id: Date.now(),
      title: title,
      completed: false
    };

    onAddTask(newTask);
    setTitle('');
  };

  return (
    <form className="task-form" onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Tambahkan tugas baru..."
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <button type="submit">Tambah</button>
    </form>
  );
}

export default TaskForm;
src/components/TaskForm/TaskForm.css
.task-form {
  display: flex;
  margin-bottom: 1.5rem;
}

.task-form input {
  flex: 1;
  padding: 0.75rem;
  border: 1px solid #ced4da;
  border-radius: 4px 0 0 4px;
  font-size: 1rem;
}

.task-form button {
  padding: 0.75rem 1.5rem;
  background-color: #28a745;
  color: white;
  border: none;
  border-radius: 0 4px 4px 0;
  cursor: pointer;
  font-size: 1rem;
  transition: background-color 0.2s;
}

.task-form button:hover {
  background-color: #218838;
}

Props Destructuring

Ada dua cara untuk menerima props dalam component:

// Langsung destructure di parameter function
function Header({ title, description }) {
  return (
    <div>
      <h1>{title}</h1>
      <p>{description}</p>
    </div>
  )
}
// Destructure di dalam function body
function Header(props) {
  const { title, description } = props;

  return (
    <div>
      <h1>{title}</h1>
      <p>{description}</p>
    </div>
  )
}

Default Props

Kalian bisa memberikan nilai default untuk props:

Default props dengan destructuring
function Header({ title = "Default Title", description }) {
  return (
    <div>
      <h1>{title}</h1>
      {description && <p>{description}</p>}
    </div>
  )
}

Conditional Rendering

Perhatikan penggunaan {description && <p>{description}</p>}. Ini adalah cara untuk render element hanya jika description ada (truthy).

Children Props

children adalah props special yang berisi konten di antara opening dan closing tag component:

Component dengan children
function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  )
}

// Penggunaan
<Card>
  <h2>Title</h2>
  <p>Content here</p>
</Card>

PropTypes - Type Checking

Untuk memastikan props yang diterima sesuai tipe yang diharapkan, gunakan PropTypes:

Install prop-types
npm install prop-types
Menggunakan PropTypes
import React from 'react';
import PropTypes from 'prop-types';

function TaskItem({ task, onDelete, onToggleComplete }) {
  return (
    // ... component code
  );
}

TaskItem.propTypes = {
  task: PropTypes.shape({
    id: PropTypes.number.isRequired,
    title: PropTypes.string.isRequired,
    completed: PropTypes.bool.isRequired
  }).isRequired,
  onDelete: PropTypes.func.isRequired,
  onToggleComplete: PropTypes.func.isRequired
};

export default TaskItem;

PropTypes di Production

PropTypes hanya melakukan checking di development mode dan tidak mempengaruhi production bundle. Untuk TypeScript, gunakan TypeScript types sebagai gantinya.

Best Practices

  1. Gunakan Destructuring - Lebih mudah dibaca dan maintainable
  2. Buat Component Kecil - Satu component satu tanggung jawab
  3. Props Read-Only - Jangan pernah modifikasi props
  4. Gunakan PropTypes atau TypeScript - Untuk type safety
  5. Meaningful Names - Gunakan nama props yang jelas dan deskriptif

Latihan

  1. Buat component Button dengan props:

    • text (string)
    • onClick (function)
    • variant ('primary' | 'secondary' | 'danger')
    • disabled (boolean, default false)
  2. Buat component UserCard dengan props:

    • user (object dengan name, email, avatar)
    • onEdit (function)
    • onDelete (function)
  3. Implementasikan PropTypes untuk kedua component di atas

Apa Selanjutnya?

Setelah memahami component dan props, kita akan belajar tentang state management dengan useState dan useEffect di bagian selanjutnya.