Membangun Aplikasi React dengan Laravel RESTful Back End: Part 2, React




Ini adalah part kedua dan terakhir dari rangkaian pembuatan aplikasi React dengan back end Laravel. Pada part pertama dari rangkaian tutorial, kita membuat RESTful API menggunakan Laravel untuk basic product-listing application. Dalam tutorial ini, kita akan mengembangkan front end menggunakan React.



Kita juga akan mempertimbangkan semua opsi yang tersedia untuk menjembatani kesenjangan antara Laravel dan React. Anda tidak perlu mengikuti salah satu bagian dari rangkaian ini untuk memahami tutorial ini. Jika Anda berada di sini untuk melihat bagaimana React dan Laravel berjalan bersama, Anda bisa, pada kenyataannya, hindari bagian pertama. Anda harus menuju ke GitHub, mengkloning ulang repo, dan mengambil catatan singkat di bawah untuk memulainya.

Pada tutorial sebelumnya, kita mengembangkan aplikasi Laravel yang merespons panggilan API. Kita membuat route, controller, dan model untukbasic product-listing application . Karena tugas controller untuk mengembalikan respons terhadap permintaan HTTP, bagian view sepenuhnya dilewati.

Kemudian kita membahas teknik penanganan dan validasi pengecualian menggunakan Laravel. Pada akhir tutorial, kita memiliki API back-end Laravel. Kini kita dapat menggunakan API ini untuk membuat aplikasi untuk web dan berbagai perangkat seluler.

Dalam tutorial ini, kita akan menggeser fokus kita ke arah front end. Bagian pertama dari tutorial ini adalah tentang pengaturan React di lingkungan kerja Laravel. Saya juga akan memperkenalkan Anda ke Laravel Mix (didukung oleh Laravel 5.4 dan setelahnya), yang merupakan API untuk mengumpulkan aset. Pada bagian kedua tutorial, kita akan mulai membangun aplikasi React dari awal.

Laravel Mix diperkenalkan di Laravel 5.4, dan saat ini merupakan cara ideal untuk menghubungkan React dan Laravel. Dengan Laravel 5.5, keseluruhan proses menjadi lebih mudah. Saya telah menjelaskan kedua metode di bawah ini.


Laravel 5.5 memiliki fitur baru yang memungkinkan Anda scaffold kode untuk komponen React menggunakan perintah command artisan preset react. Dalam versi Laravel sebelumnya, pengaturan React di dalam Laravel tidak semudah ini. Jika Anda menjalankan versi terbaru Laravel, jalankan perintah di bawah ini untuk menambahkan React preset ke proyek Anda.

1:  php artisan preset react  


Laravel secara default akan dikirim dengan Vue preset, dan perintah di atas menggantikan semua contoh Vue dengan React. Menariknya, jika Anda tidak memerlukan preset, Anda bisa menghapusnya sama sekali menggunakan perintah command  php artisan preset react none.
Jika semuanya berjalan baik, ini seharusnya muncul di terminal Anda.

1:  React scaffolding installed successfully.  
2:  Please run "npm install && npm run dev" to compile your fresh scaffolding.  


Baca Juga : Vue JS
                    JS Framework

Di background, Laravel menggunakan Laravel Mix, yang merupakan smooth wrapper untuk webpack. Webpack, seperti yang mungkin sudah Anda ketahui, adalah module bundler. Ini menyelesaikan semua dependensi modul dan menghasilkan aset statis yang diperlukan untuk JavaScript dan CSS. React membutuhkan module bundler untuk bekerja, dan webpack sangat sesuai dengan peran itu. Jadi Laravel Mix adalah layer yang berada di atas webpack dan membuatnya lebih mudah untuk menggunakan webpack di Laravel.

Pemahaman yang lebih baik tentang bagaimana cara kerja Laravel Mix sangat penting jika anda perlu menyesuaikan konfigurasi webpack saat di lain waktu. Perintah React preset memberi kita tidak ada informasi tentang bagaimana segala sesuatu bekerja di background. Jadi, mari kita hapus React preset dan menelusuri kembali langkah-langkahnya secara manual





Jika anda menjalankan Laravel 5.4, atau jika anda hanya ingin tahu bagaimana Laravel Mix dikonfigurasi, berikut adalah langkah-langkah yang harus anda ikuti:

Pasang react, react-dom dan  babel-preset-react menggunakan npm. Mungkin ide bagus untuk memasang yarn juga. Bukan rahasia lagi bahwa Laravel dan React lebih memilih yarn dibanding npm.

Menuju ke webpack.mix.js, terletak di dalam root direktori proyek Laravel anda. Ini adalah file konfigurasi dimana anda menyatakan bagaimana aset anda harus dikompilasi. Ganti baris mix.js('resources/assets/js/app.js', 'public/js'); dengan mix.react('resources/assets/js/app.js', 'public/js');. app.js adalah entry point untuk file JavaScript kita, dan file yang dikompilasi akan ditempatkan di dalam public/js. Jalankan npm install di terminal untuk memasang semua dependensi.

Selanjutnya, masuk ke resources/assets/js. Sudah ada folder komponen dan beberapa file JavaScript lainnya. Komponen react akan masuk ke dalam direktori komponen. Hapus file Example.vue yang ada dan buat file baru untuk sampel komponen React.

1:  import React, { Component } from 'react';  
2:  import ReactDOM from 'react-dom';  
3:  /* An example React component */  
4:  class Main extends Component {  
5:    render() {  
6:      return (  
7:        <div>  
8:          <h3>All Products</h3>  
9:        </div>  
10:      );  
11:    }  
12:  }  
13:  export default Main;  
14:  /* The if statement is required so as to Render the component on pages that have a div with an ID of "root";   
15:  */  
16:  if (document.getElementById('root')) {  
17:    ReactDOM.render(<Main />, document.getElementById('root'));  
18:  }  


Perbarui app.js untuk menghapus semua kode terkait Vue dan impor komponen React sebagai gantinya.

1:  require('./bootstrap');  
2:  /* Import the Main component */  
3:  import Main from './components/Main';  


Sekarang, kita hanya perlu membuat aset yang dapat diakses oleh View. File tampilan terletak di dalam direktori resources/views. Mari tambahkan <script> tag untuk welcome.blade.php, yang merupakan halaman default yang diberikan saat anda menavigasi ke localhost:8000/. Hapus isi file view dan ganti dengan kode di bawah ini:

resources/views/welcome.blade.php

1:  <!doctype html>  
2:  <html lang="{{ app()->getLocale() }}">  
3:    <head>  
4:      <meta charset="utf-8">  
5:      <meta http-equiv="X-UA-Compatible" content="IE=edge">  
6:      <meta name="viewport" content="width=device-width, initial-scale=1">  
7:      <title>Laravel React application</title>  
8:      <link href="{{mix('css/app.css')}}" rel="stylesheet" type="text/css">  
9:    </head>  
10:    <body>  
11:    <h2 style="text-align: center"> Laravel and React application </h2>  
12:      <div id="root"></div>  
13:      <script src="{{mix('js/app.js')}}" ></script>  
14:    </body>  
15:  </html>  


akhirnya, jalankan npm run dev atau yarn run dev untuk mengkompilasi aset. Jika Anda mengunjungi localhost:8000, anda seharusnya melihat:



package.json memiliki watch script yang otomatis-mengkompilasi aset ketika perubahan terdeteksi. Untuk mengaktifkan mode ini, jalankan npm run watch.

Selamat, Anda telah berhasil mengkonfigurasi React untuk bekerja dengan Laravel. Sekarang, mari kita buat beberapa komponen React untuk front ned.


Jika anda baru mengenal React, anda akan mendapati sisa dari tutorial agak menantang. Mari kita mulai!

Aplikasi React dibangun di sekitar komponen. Komponen adalah struktur terpenting dalam React, dan kita memiliki direktori yang didedikasikan untuk komponen.
Komponen membiarkan anda membagi UI menjadi potongan yang dapat diandalkan dan dapat digunakan kembali, dan memikirkan masing-masing bagian dalam isolasi. Secara konseptual, komponen seperti fungsi JavaScript. Mereka menerima masukan yg berubah-ubah (disebut "props") dan mengembalikan elemen React yang menjelaskan apa yang seharusnya muncul di layar.
— Dokumentasi Resmi React
Untuk aplikasi yang sedang kita bangun, kita akan mulai dengan komponen dasar yang menampilkan semua produk yang dikembalikan oleh server. Anggap saja itu komponen utama. Komponen harus menangani hal-hal berikut ini pada awalnya:
  • Ambil semua produk dari API (GET /api/products).
  • Simpan data produk pada state-nya.
  • Tampilkan data produk.
React bukan framework lengkap, dan karenanya library tidak memiliki fitur AJAX sendiri. Saya akan menggunakan fetch(), yang merupakan API JavaScript standar untuk mengambil data dari server. Tetapi ada banyak alternatif untuk membuat panggilan AJAX ke server.


1:  import React, { Component } from 'react';  
2:  import ReactDOM from 'react-dom';  
3:  /* Main Component */  
4:  class Main extends Component {  
5:   constructor() {  
6:    super();  
7:    //Initialize the state in the constructor  
8:    this.state = {  
9:      products: [],  
10:    }  
11:   }  
12:   /*componentDidMount() is a lifecycle method  
13:    * that gets called after the component is rendered  
14:    */  
15:   componentDidMount() {  
16:    /* fetch API in action */  
17:    fetch('/api/products')  
18:      .then(response => {  
19:        return response.json();  
20:      })  
21:      .then(products => {  
22:        //Fetched product is stored in the state  
23:        this.setState({ products });  
24:      });  
25:   }  
26:   renderProducts() {  
27:    return this.state.products.map(product => {  
28:      return (  
29:        /* When using list you need to specify a key  
30:         * attribute that is unique for each list item  
31:        */  
32:        <li key={product.id} >  
33:          { product.title }   
34:        </li>     
35:      );  
36:    })  
37:   }  
38:   render() {  
39:    /* Some css code has been removed for brevity */  
40:    return (  
41:      <div>  
42:         <ul>  
43:          { this.renderProducts() }  
44:         </ul>   
45:        </div>   
46:    );  
47:   }  
48:  }  

Di sini kita menginisialisasi state products ke array kosong di constructor. Setelah komponen dipasang, kita menggunakan fetch() untuk mengambil produk dari /api/products dan menyimpannya di dalam state-nya. Metode render digunakan untuk menggambarkan UI komponen. Semua produk bisa diberikan sebagai daftar di sana.



Halaman hanya mencantumkan judul produk, yang membosankan. Selain itu, kita belum memiliki elemen interaktif di sana. Mari membuat judul produk bisa diklik, dan saat diklik, rincian lebih lanjut tentang produk akan diberikan.






Inilah daftar hal-hal yang perlu kita bahas:

  • Sebuah state untuk melacak produk yang diklik. Mari kita sebut currentProduct dengan nilai awal null.
  • Saat judul produk diklik, this.state.currentProduct akan diperbarui.
  • Rincian produk-produk yang bersangkutan ditampilkan di sebelah kanan. Sampai sebuah produk dipilih, ini akan menampilkan pesan "Tidak ada produk yang dipilih".
  •  

1:  import React, { Component } from 'react';  
2:  import ReactDOM from 'react-dom';  
3:  /* Main Component */  
4:  class Main extends Component {  
5:   constructor() {  
6:    super();  
7:    /* currentProduct keeps track of the product currently  
8:     * displayed */  
9:    this.state = {  
10:      products: [],  
11:      currentProduct: null  
12:    }  
13:   }  
14:   componentDidMount() {  
15:    //code omitted for brevity  
16:   }  
17:   renderProducts() {  
18:    return this.state.products.map(product => {  
19:      return (  
20:        //this.handleClick() method is invoked onClick.  
21:        <li onClick={  
22:          () =>this.handleClick(product)} key={product.id} >  
23:          { product.title }   
24:        </li>     
25:      );  
26:    })  
27:   }  
28:    handleClick(product) {  
29:    //handleClick is used to set the state  
30:    this.setState({currentProduct:product});  
31:   }  
32:   render() {  
33:    /* Some css code has been removed for brevity */  
34:    return (  
35:      <div>  
36:         <ul>  
37:          { this.renderProducts() }  
38:         </ul>   
39:        </div>   
40:    );  
41:   }  
42:  }  


Di sini kita telah menambahkan createProduct ke state dan menginisialisasinya dengan nilai null. Baris onClick={ () =>this.handleClick(product) } memanggil metode handleClick() saat daftar item diklik. Metode handleClick() memperbarui state currentProduct.

Sekarang untuk menampilkan data produk, kita bisa memasukkannya ke dalam komponen Main atau membuat sebuah komponen baru. Seperti yang telah disebutkan sebelumnya, membelah UI menjadi komponen yang lebih kecil adalah cara React untuk melakukan sesuatunya. Jadi kita akan membuat komponen baru dan menamainya Product.

Komponen Product bersarang di dalam komponen Main. Komponen Main melewati state-nya sebagai alat peraga. Komponen Product menerima alat peraga ini sebagai inputan dan me-render informasi yang bersangkutan.


1:  render() {  
2:   return (  
3:    /* The extra divs are for the css styles */  
4:      <div>  
5:        <div>  
6:         <h3> All products </h3>  
7:         <ul>  
8:          { this.renderProducts() }  
9:         </ul>   
10:        </div>   
11:        <Product product={this.state.currentProduct} />  
12:      </div>  
13:    );  
14:   }  
15:  }  

1:  import React, { Component } from 'react';  
2:  /* Stateless component or pure component  
3:   * { product } syntax is the object destructing  
4:   */  
5:  const Product = ({product}) => {  
6:   const divStyle = {  
7:     /*code omitted for brevity */  
8:   }  
9:   //if the props product is null, return Product doesn't exist  
10:   if(!product) {  
11:    return(<div style={divStyle}> Product Doesnt exist </div>);  
12:   }  
13:   //Else, display the product data  
14:   return(   
15:    <div style={divStyle}>   
16:     <h2> {product.title} </h2>  
17:     <p> {product.description} </p>  
18:     <h3> Status {product.availability ? 'Available' : 'Out of stock'} </h3>  
19:     <h3> Price : {product.price} </h3>  
20:    </div>  
21:   )  
22:  }  
23:  export default Product ;  


Aplikasi akan terlihat seperti ini sekarang:




Kita telah berhasil mengimplementasikan front end yang sesuai untuk mengambil semua produk dan menampilkannya. Selanjutnya, kita memerlukan suatu form untuk menambahkan produk baru ke daftar produk. Proses untuk menambahkan produk mungkin terasa sedikit lebih rumit daripada hanya mengambil data dari API.

Inilah yang saya pikir diperlukan untuk mengembangkan fitur ini:

  • Komponen stateful baru yang me-render UI untuk sebuah form input. State komponen menyimpan data form.
  • Saat disubmit, komponen anak melewati state ke komponen Main menggunakan callback.
  • Komponen Main memiliki sebuah metode, katakanlah handleNewProduct(), yang menangani logika untuk memulai permintaan POST. Setelah menerima tanggapan, komponen Main memperbarui state-nya (baik this.state.products dan this.state.currentProduct)
Itu tidak terdengar sangat rumit, bukan? Mari kita lakukan langkah demi langkah. Pertama, buat komponen baru. Saya akan menyebutnya AddProduct.


1:  class AddProduct extends Component {  
2:   constructor(props) {  
3:    super(props);  
4:      /* Initialize the state. */  
5:      this.state = {  
6:       newProduct: {  
7:         title: '',  
8:         description: '',  
9:         price: 0,  
10:         availability: 0  
11:       }  
12:      }  
13:    //Boilerplate code for binding methods with `this`  
14:    this.handleSubmit = this.handleSubmit.bind(this);  
15:    this.handleInput = this.handleInput.bind(this);  
16:   }  
17:   /* This method dynamically accepts inputs and stores it in the state */  
18:   handleInput(key, e) {  
19:    /*Duplicating and updating the state */  
20:    var state = Object.assign({}, this.state.newProduct);   
21:    state[key] = e.target.value;  
22:    this.setState({newProduct: state });  
23:   }  
24:   /* This method is invoked when submit button is pressed */  
25:   handleSubmit(e) {  
26:    //preventDefault prevents page reload    
27:    e.preventDefault();  
28:    /*A call back to the onAdd props. The current  
29:     *state is passed as a param  
30:     */  
31:    this.props.onAdd(this.state.newProduct);  
32:   }  
33:   render() {  
34:    const divStyle = {  
35:      /*Code omitted for brevity */ }  
36:    return(  
37:     <div>   
38:      <h2> Add new product </h2>  
39:      <div style={divStyle}>   
40:      /*when Submit button is pressed, the control is passed to   
41:       *handleSubmit method   
42:       */  
43:      <form onSubmit={this.handleSubmit}>  
44:       <label> Title:   
45:        { /*On every keystroke, the handeInput method is invoked */ }  
46:        <input type="text" onChange={(e)=>this.handleInput('title',e)} />  
47:       </label>  
48:       <label> Description:   
49:        <input type="text" onChange={(e)=>this.handleInput('description',e)} />  
50:       </label>  
51:       { /* Input fields for Price and availability omitted for brevity */}  
52:       <input type="submit" value="Submit" />  
53:      </form>  
54:     </div>  
55:    </div>)  
56:   }  
57:  }  
58:  export default AddProduct;  

Komponen pada dasarnya me-render sebuah form input, dan semua nilai masukan yang disimpan di state (this.state.newProduct). Kemudian, pada form pengajuan, metode handleSubmit() akan dipanggil. Tetapi AddProduct perlu mengkomunikasikan informasi yang kembali ke induk dan kita melakukannya dengan menggunakan callback.

Komponen Main, yang merupakan induk, melewati referensi fungsi sebagai alat peraga. Komponen anak, AddProduct dalam kasus kita, memanggil alat peraga ini untuk memberitahu induk dari perubahan state. Jadi baris this.props.onAdd(this.state.newProduct); adalah contoh callback yang memberitahu komponen induk dari produk baru.

Sekarang, di dalam komponen Main, kita akan menyatakan <AddProduct /> sebagai berikut:


1:  <AddProduct onAdd={this.handleAddProduct} />  

Event handler OnAdd dikaitkan ke metode komponen handleAddProduct(). Metode ini menempati kode untuk membuat permintaan POST ke server. Jika respon menunjukkan bahwa produk telah berhasil dibuat, state products dan currentProducts akan diperbarui.

1:  handleAddProduct(product) {  
2:    product.price = Number(product.price);  
3:    /*Fetch API for post request */  
4:    fetch( 'api/products/', {  
5:      method:'post',  
6:      /* headers are important*/  
7:      headers: {  
8:       'Accept': 'application/json',  
9:       'Content-Type': 'application/json'  
10:      },  
11:      body: JSON.stringify(product)  
12:    })  
13:    .then(response => {  
14:      return response.json();  
15:    })  
16:    .then( data => {  
17:      //update the state of products and currentProduct  
18:      this.setState((prevState)=> ({  
19:        products: prevState.products.concat(data),  
20:        currentProduct : data  
21:      }))  
22:    })  
23:   }  

Jangan lupa untuk mengikat metode handleProduct ke kelas menggunakan this.handleAddProduct = this.handleAddProduct.bind(this); di dalam konstruktor. Dan ini adalah versi final dari aplikasi:




Aplikasi tidak lengkap tanpa fitur hapus dan ubah. Tetapi jika anda sudah mengikuti tutorial dengan teliti sampai sekarang, Anda harus mampu mengisi kekosongan tanpa banyak kesulitan. Untuk anda memulai, Saya telah menyediakan logika event handler untuk skenario hapus dan ubah.


1:  handleDelete() {  
2:   const currentProduct = this.state.currentProduct;  
3:   fetch( 'api/products/' + this.state.currentProduct.id,   
4:     { method: 'delete' })  
5:     .then(response => {  
6:      /* Duplicate the array and filter out the item to be deleted */  
7:      var array = this.state.products.filter(function(item) {  
8:      return item !== currentProduct  
9:     });  
10:     this.setState({ products: array, currentProduct: null});  
11:   });  
12:  }  

1:  handleUpdate(product) {  
2:    const currentProduct = this.state.currentProduct;  
3:    fetch( 'api/products/' + currentProduct.id, {  
4:      method:'put',  
5:      headers: {  
6:       'Accept': 'application/json',  
7:       'Content-Type': 'application/json'  
8:      },  
9:      body: JSON.stringify(product)  
10:    })  
11:    .then(response => {  
12:      return response.json();  
13:    })  
14:    .then( data => {  
15:      /* Updating the state */  
16:      var array = this.state.products.filter(function(item) {  
17:       return item !== currentProduct  
18:     })  
19:      this.setState((prevState)=> ({  
20:        products: array.concat(product),  
21:        currentProduct : product  
22:      }))  
23:    })   
24:   }  


Apa yang perlu anda lakukan adalah menyelaminya lebih dalam, biarkan tangan anda kotor dan selesaikan aplikasi dengan menggunakan logika diatas. Saya akan menunrunkan anda suatu petunjuk: tombol hapus idealnya harus masuk ke dalam komponen Product, sedangkan fitur ubah harus memiliki komponen sendiri. Saya mendorong anda untuk mengambil tantangan ini dan menyelesaikan komponen yang hilang.


Kita telah melangkah jauh dari saat dimana kita memulai. Pertama, kita menciptakan sebuah REST API menggunakan framework Laravel. Kemudian, kita mendiskusikan pilihan kita untuk menggabungkan Laravel dan React. Yang Terakhir, kita membangun sebuah front end ke API menggunakan React.

Meskipun semula kita fokus untuk membuat aplikasi satu-halaman menggunakan React, anda bisa membuat widget atau komponen yang dipasang untuk unsur-unsur tertentu di view anda. React sangat fleksibel karena ini sebuah library, dan salah satu yang bagus.

Selama beberapa tahun terakhir, React telah tumbuh dalam popularitas. Bahkan, kami telah memiliki sejumlah item di marketplace yang tersedia untuk pembelian, peninjauan, implementasi, dan sebagainya. Jika anda sedang mencari sumber-sumber tambahan seputar React, jangan ragu untuk memeriksanya.

Apakah anda mencoba bereksperimen dengan Laravel dan React sebelumnya? Apa yang anda pikirkan? Berbagilah dengan kami di komentar.