Membangun Editor Kode Web
Diterbitkan: 2022-03-10Editor kode web online paling berguna saat Anda tidak memiliki kesempatan untuk menggunakan aplikasi editor kode, atau saat Anda ingin mencoba sesuatu di web dengan komputer atau bahkan ponsel Anda dengan cepat. Ini juga merupakan proyek yang menarik untuk dikerjakan karena memiliki pengetahuan tentang cara membuat editor kode akan memberi Anda ide tentang cara mendekati proyek lain yang mengharuskan Anda mengintegrasikan editor kode untuk menunjukkan beberapa fungsionalitas.
Berikut adalah beberapa konsep React yang perlu Anda ketahui untuk mengikuti artikel ini:
- kait,
- Struktur komponen,
- komponen fungsional,
- Atribut.
Menggunakan CodeMirror
Kami akan menggunakan perpustakaan bernama CodeMirror untuk membangun editor kami. CodeMirror adalah editor teks serbaguna yang diimplementasikan dalam JavaScript untuk browser. Ini terutama untuk mengedit kode dan dilengkapi dengan sejumlah mode bahasa dan add-on untuk fungsionalitas pengeditan lebih lanjut.
API pemrograman yang kaya dan sistem tema CSS tersedia untuk menyesuaikan CodeMirror agar sesuai dengan aplikasi Anda dan memperluasnya dengan fungsionalitas baru. Ini memberi kita fungsionalitas untuk membuat editor kode kaya yang berjalan di web dan menunjukkan kepada kita hasil kode kita secara real time.
Di bagian selanjutnya, kita akan menyiapkan proyek React baru kita dan menginstal perpustakaan yang kita butuhkan untuk membangun aplikasi web kita.
Membuat Proyek React Baru
Mari kita mulai dengan membuat proyek React baru. Di antarmuka baris perintah Anda, navigasikan ke direktori di mana Anda ingin membuat proyek Anda, dan mari buat aplikasi React dan beri nama code_editor
:
npx create-react-app code_editor
Setelah membuat aplikasi React baru, mari navigasikan ke direktori proyek tersebut di antarmuka baris perintah:
cd code_editor
Ada dua perpustakaan yang perlu kita instal di sini: codemirror
dan react-codemirror2
.
npm install codemirror react-codemirror2
Setelah menginstal perpustakaan yang kita butuhkan untuk proyek ini, mari buat tab kita dan aktifkan peralihan tab di antara tiga tab yang akan muncul di editor kita (untuk HTML, CSS, dan JavaScript).
Komponen Tombol
Alih-alih membuat tombol individual, mari jadikan tombol sebagai komponen yang dapat digunakan kembali. Dalam proyek kami, tombol akan memiliki tiga contoh, sesuai dengan tiga tab yang kami butuhkan.
Buat folder bernama components
di folder src
. Di folder components
baru ini, buat file JSX bernama Button.jsx
.
Berikut adalah semua kode yang dibutuhkan dalam komponen Button
:
import React from 'react' const Button = ({title, onClick}) => { return ( <div> <button style={{ maxWidth: "140px", minWidth: "80px", height: "30px", marginRight: "5px" }} onClick={onClick} > {title} </button> </div> ) } export default Button
Berikut adalah penjelasan lengkap dari apa yang kami lakukan di atas:
- Kami membuat komponen fungsional bernama
Button
, yang kemudian kami ekspor. - Kami merusak
title
danonClick
dari props yang masuk ke komponen. Di sini,title
akan menjadi string teks, danonClick
akan menjadi fungsi yang dipanggil saat tombol diklik. - Selanjutnya, kami menggunakan elemen
button
untuk mendeklarasikan tombol kami, dan menggunakan atributstyle
untuk menata tombol kami agar terlihat rapi. - Kami menambahkan atribut
onClick
dan meneruskan alat peraga fungsionClick
kami yang telah dirusak ke dalamnya. - Hal terakhir yang Anda perhatikan kami lakukan di komponen ini adalah meneruskan
{title}
sebagai konten dari tagbutton
. Ini memungkinkan kita untuk menampilkan judul secara dinamis, berdasarkan prop apa yang diteruskan ke instance komponen tombol saat dipanggil.
Sekarang kita telah membuat komponen tombol yang dapat digunakan kembali, mari kita lanjutkan dan membawa komponen kita ke App.js.
Buka App.js
dan impor komponen tombol yang baru dibuat:
import Button from './components/Button';
Untuk melacak tab atau editor mana yang terbuka, kita memerlukan status deklarasi untuk menyimpan nilai editor yang terbuka. Menggunakan kait useState
React, kita akan mengatur status yang akan menyimpan nama tab editor yang saat ini terbuka saat tombol tab itu diklik.
Inilah cara kami melakukannya:
import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { const [openedEditor, setOpenedEditor] = useState('html'); return ( <div className="App"> </div> ); } export default App;
Di sini, kami menyatakan negara kami. Dibutuhkan nama editor yang sedang terbuka. Karena nilai html
diteruskan sebagai nilai default negara bagian, editor HTML akan menjadi tab yang terbuka secara default.
Mari kita lanjutkan dan tulis fungsi yang akan menggunakan setOpenedEditor
untuk mengubah nilai status saat tombol tab diklik.
Catatan: Dua tab mungkin tidak terbuka secara bersamaan, jadi kita harus mempertimbangkannya saat menulis fungsi kita.
Inilah fungsi kami, bernama onTabClick
, terlihat seperti:
import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { ... const onTabClick = (editorName) => { setOpenedEditor(editorName); }; return ( <div className="App"> </div> ); } export default App;
Di sini, kami melewati argumen fungsi tunggal, yang merupakan nama tab yang saat ini dipilih. Argumen ini akan diberikan di mana pun fungsi dipanggil, dan nama yang relevan dari tab itu akan diteruskan.
Mari buat tiga instance Button
untuk tiga tab yang kita butuhkan:
<div className="App"> <p>Welcome to the editor!</p> <div className="tab-button-container"> <Button title="HTML" onClick={() => { onTabClick('html') }} /> <Button title="CSS" onClick={() => { onTabClick('css') }} /> <Button title="JavaScript" onClick={() => { onTabClick('js') }} /> </div> </div>
Inilah yang kami lakukan:
- Kami mulai dengan menambahkan tag
p
, pada dasarnya hanya untuk memberikan beberapa konteks tentang apa aplikasi kami. - Kami menggunakan tag
div
untuk membungkus tombol tab kami. Tagdiv
membawaclassName
yang akan kita gunakan untuk menata tombol menjadi tampilan grid di file CSS nanti dalam tutorial ini. - Selanjutnya, kami mendeklarasikan tiga instance dari komponen
Button
. Jika Anda ingat, komponenButton
membutuhkan dua props,title
danonClick
. Dalam setiap instance komponenButton
, kedua props ini disediakan. -
title
prop mengambil judul tab. - Prop
onClick
mengambil fungsi,onTabClick
, yang baru saja kita buat dan yang mengambil satu argumen: nama tab yang dipilih.
Berdasarkan tab yang saat ini dipilih, kami akan menggunakan operator ternary JavaScript untuk menampilkan tab secara kondisional. Ini berarti bahwa jika nilai dari status openedEditor
diatur ke html
(yaitu setOpenedEditor('html')
), maka tab untuk bagian HTML akan menjadi tab yang terlihat saat ini. Anda akan memahami ini dengan lebih baik seperti yang kami lakukan di bawah ini:
... return ( <div className="App"> ... <div className="editor-container"> { openedEditor === 'html' ? ( <p>The html editor is open</p> ) : openedEditor === 'css' ? ( <p>The CSS editor is open!!!!!!</p> ) : ( <p>the JavaScript editor is open</p> ) } </div> </div> ); ...
Mari kita bahas kode di atas dalam bahasa Inggris yang sederhana. Jika nilai openedEditor
adalah html
, maka tampilkan bagian HTML. Jika tidak, jika nilai dari openedEditor
adalah css
, maka tampilkan bagian CSS. Jika tidak, jika nilainya bukan html
atau css
, maka itu berarti nilainya harus js
, karena kita hanya memiliki tiga kemungkinan nilai untuk status openedEditor
; jadi, maka kami akan menampilkan tab untuk JavaScript.
Kami menggunakan tag paragraf ( p
) untuk bagian yang berbeda dalam kondisi operator ternary. Saat kita melanjutkan, kita akan membuat komponen editor dan mengganti tag p
dengan komponen editor itu sendiri.
Kami telah sampai sejauh ini! Ketika sebuah tombol diklik, itu menjalankan tindakan yang menyetel tab yang diwakilinya menjadi true
, membuat tab itu terlihat. Berikut tampilan aplikasi kami saat ini:
Mari tambahkan sedikit CSS ke wadah div
yang menahan tombol. Kami ingin tombol ditampilkan dalam kotak, alih-alih ditumpuk secara vertikal seperti pada gambar di atas. Buka file App.css
Anda dan tambahkan kode berikut:
.tab-button-container{ display: flex; }
Ingatlah bahwa kita menambahkan className="tab-button-container"
sebagai atribut dalam tag div
yang menahan tombol tiga-tab. Di sini, kami memberi gaya pada wadah itu, menggunakan CSS untuk mengatur tampilannya menjadi flex
. Ini adalah hasilnya:
Banggalah dengan seberapa banyak yang telah Anda lakukan untuk sampai ke titik ini. Di bagian selanjutnya, kami akan membuat editor kami, mengganti tag p
dengan mereka.
Membuat Editor
Karena kita telah menginstal perpustakaan yang akan kita kerjakan di dalam editor CodeMirror kita, mari kita buat file Editor.jsx
kita di folder components
.
komponen > Editor.jsx
Setelah membuat file baru kita, mari kita tulis beberapa kode awal di dalamnya:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> </div> ) } export default Editor
Inilah yang kami lakukan:
- Kami mengimpor React bersama hook
useState
karena kami akan membutuhkannya. - Kami mengimpor file CSS CodeMirror (yang berasal dari perpustakaan CodeMirror yang kami instal, jadi Anda tidak perlu menginstalnya dengan cara khusus).
- Kami mengimpor
Controlled
darireact-codemirror2
, mengganti namanya menjadiControlledEditorComponent
untuk membuatnya lebih jelas. Kami akan segera menggunakan ini. - Kemudian, kami mendeklarasikan komponen fungsional
Editor
kami, dan kami memiliki pernyataan return dengandiv
kosong, denganclassName
dalam pernyataan return untuk saat ini.
Dalam komponen fungsional kami, kami merusak beberapa nilai dari props, termasuk language
, value
, dan setEditorState
. Ketiga props ini akan diberikan dalam setiap instance editor saat dipanggil di App.js
.
Mari kita gunakan ControlledEditorComponent
untuk menulis kode untuk editor kita. Inilah yang akan kami lakukan:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, }} /> </div> ) } export default Editor
Mari kita telusuri apa yang kita lakukan di sini, menjelaskan beberapa istilah CodeMirror.
Mode CodeMirror menentukan bahasa yang dimaksudkan untuk editor. Kami mengimpor tiga mode karena kami memiliki tiga editor untuk proyek ini:
- XML: Mode ini untuk HTML. Ini menggunakan istilah XML.
- JavaScript: Ini (
codemirror/mode/javascript/javascript
) membawa mode JavaScript. - CSS: Ini (
codemirror/mode/css/css
) membawa mode CSS.
Catatan: Karena editor dibuat sebagai komponen yang dapat digunakan kembali, kami tidak dapat menempatkan mode langsung di editor. Jadi, kami menyediakan mode melalui prop language
yang kami destruktur. Tetapi ini tidak mengubah fakta bahwa mode perlu diimpor agar berfungsi.
Selanjutnya, mari kita bahas hal-hal di ControlledEditorComponent
:
-
onBeforeChange
Ini dipanggil kapan saja Anda menulis atau menghapus dari editor. Pikirkan ini seperti handleronChange
yang biasanya Anda miliki di bidang input untuk melacak perubahan. Dengan menggunakan ini, kita akan bisa mendapatkan nilai editor kita kapan saja ada perubahan baru dan menyimpannya ke status editor kita. Kami akan menulis fungsi{handleChange}
saat kami melanjutkan. -
value = {value}
Ini hanyalah konten editor pada waktu tertentu. Kami meneruskanvalue
bernama prop yang didestruktur ke atribut ini. Alat peragavalue
adalah status yang memegang nilai editor itu. Ini akan diberikan dari contoh editor. -
className
="code-mirror-wrapper"
Nama kelas ini bukan gaya yang kami buat sendiri. Itu dipasok dari file CSS CodeMirror, yang kami impor di atas. -
options
Ini adalah objek yang mengambil fungsi berbeda yang kita inginkan untuk dimiliki oleh editor kita. Ada banyak opsi luar biasa di CodeMirror. Mari kita lihat yang kami gunakan di sini:-
lineWrapping: true
Ini berarti bahwa kode harus membungkus ke baris berikutnya ketika baris sudah penuh. -
lint: true
Ini memungkinkan linting. -
mode: language
Mode ini, seperti yang dibahas di atas, menggunakan bahasa yang akan digunakan editor. Bahasa telah diimpor di atas, tetapi editor akan menerapkan bahasa berdasarkan nilailanguage
yang diberikan ke editor melalui prop. -
lineNumbers: true
Ini menentukan bahwa editor harus memiliki nomor baris untuk setiap baris.
-
Selanjutnya, kita dapat menulis fungsi handleChange
untuk handler onBeforeChange
:
const handleChange = (editor, data, value) => { setEditorState(value); }
Handler onBeforeChange
memberi kita akses ke tiga hal: editor, data, value
.
Kami hanya membutuhkan value
karena itulah yang ingin kami sampaikan di prop setEditorState
kami. Prop setEditorState
mewakili nilai yang ditetapkan untuk setiap status yang kami deklarasikan di App.js
, yang menyimpan nilai untuk setiap editor. Saat kita melanjutkan, kita akan melihat bagaimana meneruskan ini sebagai prop ke komponen Editor
.
Selanjutnya, kita akan menambahkan dropdown yang memungkinkan kita memilih tema yang berbeda untuk editor. Jadi, mari kita lihat tema di CodeMirror.
Tema CodeMirror
CodeMirror memiliki beberapa tema yang dapat kita pilih. Kunjungi situs web resmi untuk melihat demo berbagai tema yang tersedia. Mari buat dropdown dengan tema berbeda yang dapat dipilih pengguna di editor kami. Untuk tutorial ini, kami akan menambahkan lima tema, tetapi Anda dapat menambahkan sebanyak yang Anda suka.
Pertama, mari impor tema kita di komponen Editor.js
:
import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css';
Selanjutnya, buat larik dari semua tema yang telah kita impor:
const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']
Mari deklarasikan kait useState
untuk menyimpan nilai tema yang dipilih, dan atur tema default sebagai dracula
:
const [theme, setTheme] = useState("dracula")
Mari kita buat dropdown:
... return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="cars">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> // the rest of the code comes below... </div> ) ...
Pada kode di atas, kami menggunakan tag HTML label
untuk menambahkan label ke dropdown kami, dan kemudian menambahkan tag HTML select
untuk membuat dropdown kami. Tag option
di elemen select
mendefinisikan opsi yang tersedia di dropdown.
Karena kita perlu mengisi dropdown dengan nama tema di themeArray
yang kita buat, kita menggunakan metode array .map
untuk memetakan themeArray
dan menampilkan nama secara individual menggunakan tag option
.
Tunggu — kita belum selesai menjelaskan kode di atas. Di tag select
pembuka, kami meneruskan atribut onChange
untuk melacak dan memperbarui status theme
setiap kali nilai baru dipilih di dropdown. Setiap kali opsi baru dipilih di dropdown, nilainya didapat dari objek yang dikembalikan kepada kami. Selanjutnya, kami menggunakan setTheme
dari kait status kami untuk menetapkan nilai baru menjadi nilai yang dimiliki status.
Pada titik ini, kami telah membuat dropdown kami, mengatur status tema kami, dan menulis fungsi kami untuk mengatur status dengan nilai baru. Hal terakhir yang perlu kita lakukan untuk membuat CodeMirror menggunakan tema kita adalah meneruskan tema ke objek options
di ControlledEditorComponent
. Di objek options
, mari tambahkan nilai bernama theme
, dan atur nilainya ke nilai status untuk tema yang dipilih, juga bernama theme
.
Inilah yang akan terlihat seperti ControlledEditorComponent
sekarang:
<ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} />
Sekarang, kami telah membuat dropdown dari berbagai tema yang dapat dipilih dari dalam editor.
Berikut tampilan kode lengkap di Editor.js
saat ini:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { const [theme, setTheme] = useState("dracula") const handleChange = (editor, data, value) => { setEditorState(value); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="themes">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} /> </div> ) } export default Editor
Hanya ada satu className
yang perlu kita gaya. Buka App.css
dan tambahkan gaya berikut:
.editor-container{ padding-top: 0.4%; }
Sekarang setelah editor kita siap, mari kembali ke App.js
dan menggunakannya di sana.
src > App.js
Hal pertama yang perlu kita lakukan adalah mengimpor komponen Editor.js
di sini:
import Editor from './components/Editor';
Di App.js
, mari kita nyatakan status yang masing-masing akan menampung konten editor HTML, CSS, dan JavaScript.
const [html, setHtml] = useState(''); const [css, setCss] = useState(''); const [js, setJs] = useState('');
Jika Anda ingat, kami perlu menggunakan status ini untuk menyimpan dan memasok konten editor kami.
Selanjutnya, mari kita ganti tag paragraf ( p
) yang kita gunakan untuk HTML, CSS, dan JavaScript dalam rendering bersyarat dengan komponen editor yang baru saja kita buat, dan kita juga akan meneruskan prop yang sesuai ke setiap instance editor komponen:
function App() { ... return ( <div className="App"> <p>Welcome to the edior</p> // This is where the tab buttons container is... <div className="editor-container"> { htmlEditorIsOpen ? ( <Editor language="xml" value={html} setEditorState={setHtml} /> ) : cssEditorIsOpen ? ( <Editor language="css" value={css} setEditorState={setCss} /> ) : ( <Editor language="javascript" value={js} setEditorState={setJs} /> ) } </div> </div> ); } export default App;
Jika Anda telah mengikuti sampai sekarang, Anda akan memahami apa yang kami lakukan di blok kode di atas.
Ini dia dalam bahasa Inggris yang sederhana: Kami mengganti tag p
(yang ada di sana sebagai pengganti) dengan komponen editor. Kemudian, kami menyediakan props language
, value
, dan setEditorState
, masing-masing, agar sesuai dengan statusnya.
Kami sudah sejauh ini! Inilah tampilan aplikasi kami sekarang:
Pengantar Iframe
Kita akan menggunakan inline frames (iframes) untuk menampilkan hasil dari kode yang dimasukkan dalam editor.
Menurut MDN:
Elemen HTML Inline Frame (
<iframe>
) mewakili konteks penelusuran bersarang, menyematkan halaman HTML lain ke halaman saat ini.
Bagaimana Iframe Bekerja di React
Iframe biasanya digunakan dengan HTML biasa. Menggunakan Iframes dengan React tidak memerlukan banyak perubahan, yang utama adalah mengubah nama atribut menjadi camelcase. Contohnya adalah bahwa srcdoc
akan menjadi srcDoc
.
Masa Depan Iframe di Web
Iframe terus menjadi sangat berguna dalam pengembangan web. Sesuatu yang mungkin ingin Anda periksa adalah Portal. Seperti yang dijelaskan Daniel Brain:
“Portal memperkenalkan serangkaian kemampuan baru yang kuat ke dalam campuran ini. Sekarang mungkin untuk membangun sesuatu yang terasa seperti iframe, yang dapat dengan mulus menganimasikan dan berubah dan mengambil alih jendela browser penuh.”
Salah satu hal yang coba dipecahkan oleh Portal adalah masalah bilah URL. Saat menggunakan iframe, komponen yang dirender di iframe tidak membawa URL unik di bilah alamat; dengan demikian, ini mungkin tidak bagus untuk pengalaman pengguna, tergantung pada kasus penggunaan. Portal layak untuk dicoba, dan saya sarankan Anda melakukannya, tetapi karena itu bukan fokus artikel kami, hanya ini yang akan saya katakan di sini.
Membuat Iframe untuk Menampung Hasil Kami
Mari kita lanjutkan tutorial kita dengan membuat iframe untuk menampung hasil editor kita.
return ( <div className="App"> // ... <div> <iframe srcDoc={srcDoc} title="output" sandbox="allow-scripts" frameBorder="1" width="100%" height="100%" /> </div> </div> );
Di sini, kami membuat iframe dan menyimpannya di tag wadah div
. Di iframe, kami melewati beberapa atribut yang kami butuhkan:
-
srcDoc
AtributsrcDoc
ditulis dalam camelcase karena ini adalah cara menulis atribut iframe di React. Saat menggunakan iframe, kita dapat menyematkan halaman web eksternal pada halaman atau merender konten HTML tertentu. Untuk memuat dan menyematkan halaman eksternal, kita akan menggunakan propertisrc
sebagai gantinya. Dalam kasus kami, kami tidak memuat halaman eksternal; alih-alih, kami ingin membuat dokumen HTML internal baru yang menampung hasil kami; untuk ini, kita memerlukan atributsrcDoc
. Atribut ini mengambil dokumen HTML yang ingin kita sematkan (kita belum membuatnya, tapi akan segera kita buat). -
title
Atribut title digunakan untuk mendeskripsikan isi dari inline frame. -
sandbox
Properti ini memiliki banyak tujuan. Dalam kasus kami, kami menggunakannya untuk mengizinkan skrip berjalan di iframe kami dengan nilaiallow-scripts
. Karena kami bekerja dengan editor JavaScript, ini akan berguna dengan cepat. -
frameBorder
Ini hanya mendefinisikan ketebalan batas iframe. -
width
danheight
Ini mendefinisikan lebar dan tinggi iframe.
Istilah-istilah ini sekarang seharusnya lebih masuk akal bagi Anda. Mari kita lanjutkan dan mendeklarasikan status yang akan menampung dokumen template HTML untuk srcDoc
. Jika Anda melihat lebih dekat pada blok kode di atas, Anda akan melihat bahwa kami memberikan nilai ke atribut srcDoc
: srcDoc
={srcDoc}
. Mari gunakan useState()
React kita untuk mendeklarasikan status srcDoc
. Untuk melakukan ini, di file App.js
, buka tempat kami mendefinisikan status lainnya dan tambahkan yang ini:
const [srcDoc, setSrcDoc] = useState(` `);
Sekarang setelah kita membuat status, hal selanjutnya yang harus dilakukan adalah menampilkan hasilnya dalam status setiap kali kita mengetik di editor kode. Tetapi yang tidak kami inginkan adalah merender ulang komponen pada setiap penekanan tombol. Dengan mengingat hal itu, mari kita lanjutkan.
Mengonfigurasi Iframe untuk Menampilkan Hasil
Setiap kali ada perubahan di salah satu editor untuk HTML, CSS, dan JavaScript, kami ingin useEffect()
dipicu, dan itu akan membuat hasil yang diperbarui di iframe. Mari kita tulis useEffect()
untuk melakukan ini di file App.js
:
Pertama, impor kait useEffect()
:
import React, { useState, useEffect } from 'react';
Mari kita tulis useEffect()
seperti ini:
useEffect(() => { const timeOut = setTimeout(() => { setSrcDoc( ` <html> <body>${html}</body> <style>${css}</style> <script>${js}</script> </html> ` ) }, 250); return () => clearTimeout(timeOut) }, [html, css, js])
Di sini, kami menulis kait useEffect()
yang akan selalu berjalan setiap kali nilai menyatakan yang kami nyatakan untuk editor HTML, CSS, dan JavaScript diubah atau diperbarui.
Mengapa kita perlu menggunakan setTimeout()
? Nah, jika kami menulis ini tanpa itu, maka setiap kali satu tombol ditekan di editor, iframe kami akan diperbarui, dan itu tidak bagus untuk kinerja secara umum. Jadi kami menggunakan setTimeout()
untuk menunda pembaruan selama 250 milidetik, memberi kami cukup waktu untuk mengetahui apakah pengguna masih mengetik. Artinya, setiap kali pengguna menekan tombol, hitungan akan dimulai ulang, sehingga iframe hanya akan diperbarui ketika pengguna dalam keadaan diam (tidak mengetik) selama 250 milidetik. Ini adalah cara yang keren untuk menghindari keharusan memperbarui iframe setiap kali tombol ditekan.
Hal berikutnya yang kami lakukan di atas adalah memperbarui srcDoc
dengan perubahan baru. Komponen srcDoc
, seperti yang kami jelaskan di atas, merender konten HTML tertentu di iframe. Dalam kode kami, kami melewati template HTML, mengambil status html
yang berisi kode yang telah diketik pengguna ke dalam editor HTML dan menempatkannya di antara tag body
template kami. Kami juga mengambil status css
yang berisi gaya yang diketik pengguna di editor CSS, dan kami meneruskannya di antara tag style
. Terakhir, kami mengambil status js
yang berisi kode JavaScript yang telah diketik pengguna di editor JavaScript, dan kami meneruskannya di antara tag script
.
Perhatikan bahwa dalam menyetel setSrcDoc
, kita menggunakan backticks ( ` `
) alih-alih tanda kutip normal ( ' '
). Ini karena backticks memungkinkan kita untuk meneruskan nilai status yang sesuai, seperti yang kita lakukan pada kode di atas.
Pernyataan return
di kait useEffect()
adalah fungsi pembersihan yang menghapus setTimeout()
saat selesai, untuk menghindari kebocoran memori. Dokumentasi memiliki lebih banyak tentang useEffect
.
Inilah yang tampak seperti proyek kami saat ini:
Addons CodeMirror
Dengan add-on CodeMirror, kami dapat meningkatkan editor kami dengan lebih banyak fungsi yang akan kami temukan di editor kode lainnya. Mari kita telusuri contoh tag penutup yang ditambahkan secara otomatis saat tag pembuka diketik, dan contoh lain dari tanda kurung tutup secara otomatis saat tanda kurung buka dimasukkan:
Hal pertama yang harus dilakukan adalah mengimpor addon untuk ini ke file App.js
kami:
import 'codemirror/addon/edit/closetag'; import 'codemirror/addon/edit/closebrackets';
Mari kita berikan dalam opsi ControlledEditorComponent
:
<ControlledEditorComponent ... options={{ ... autoCloseTags: true, autoCloseBrackets: true, }} />
Sekarang inilah yang kita miliki:
Anda dapat menambahkan satu ton add-on ini ke editor Anda untuk memberikan fitur yang lebih kaya. Kami tidak mungkin melewati semuanya di sini.
Sekarang setelah kita selesai dengan ini, mari kita bahas secara singkat hal-hal yang dapat kita lakukan untuk meningkatkan aksesibilitas dan kinerja aplikasi kita.
Performa dan Aksesibilitas Solusi
Melihat editor kode web kami, beberapa hal pasti dapat diperbaiki.
Karena kami lebih memperhatikan fungsionalitas, kami mungkin sedikit mengabaikan desain. Untuk aksesibilitas yang lebih baik, berikut adalah beberapa hal yang dapat Anda lakukan untuk meningkatkan solusi ini:
- Anda dapat mengatur kelas
active
pada tombol untuk editor yang sedang terbuka. Menyoroti tombol akan meningkatkan aksesibilitas dengan memberi pengguna indikasi yang jelas tentang editor mana yang sedang mereka kerjakan. - Anda mungkin ingin editor menempati lebih banyak ruang layar daripada yang kami miliki di sini. Hal lain yang dapat Anda coba adalah membuat iframe muncul dengan mengklik tombol yang ditambatkan di suatu tempat ke samping. Melakukannya akan memberi editor lebih banyak ruang layar.
- Editor semacam ini akan berguna bagi orang yang ingin menjalankan latihan cepat di perangkat seluler mereka, jadi perlu menyesuaikan sepenuhnya dengan seluler (belum lagi kedua poin tentang seluler di atas).
- Saat ini, kami dapat mengganti tema komponen editor dari beberapa tema yang kami muat, tetapi tema umum halaman tetap sama. Anda dapat mengaktifkan pengguna untuk beralih antara tema gelap dan terang untuk seluruh tata letak. Ini akan bagus untuk aksesibilitas, menghilangkan ketegangan pada mata orang karena melihat layar yang terang terlalu lama.
- Kami tidak melihat masalah keamanan dengan iframe kami, terutama karena kami memuat dokumen HTML internal di iframe, bukan dokumen eksternal. Jadi kita tidak perlu mempertimbangkan ini terlalu hati-hati karena iframe sangat cocok untuk use case kita.
- Dengan iframe, pertimbangan lain adalah waktu pemuatan halaman, karena konten yang dimuat di iframe biasanya berada di luar kendali Anda. Di aplikasi kami, ini bukan masalah karena konten iframe kami tidak eksternal.
Performa dan aksesibilitas sangat penting untuk dipertimbangkan saat Anda membangun aplikasi apa pun karena keduanya akan menentukan seberapa berguna dan dapat digunakannya aplikasi Anda bagi penggunanya.
Shedrack telah melakukan pekerjaan yang baik dalam menjelaskan metode untuk meningkatkan dan mengoptimalkan kinerja di aplikasi React. Layak untuk dicoba!
Kesimpulan
Bekerja melalui proyek yang berbeda membantu kita untuk belajar tentang berbagai mata pelajaran. Sekarang setelah Anda membaca artikel ini, jangan ragu untuk memperluas pengalaman Anda dengan bereksperimen dengan lebih banyak add-on untuk membuat editor kode lebih kaya, memperbarui UI, dan memperbaiki masalah aksesibilitas dan kinerja yang diuraikan di atas.
- Seluruh basis kode untuk proyek ini tersedia di GitHub.
Berikut demo di Codesandbox:
Tautan dan Materi
- “Portal Google Chrome: Seperti Iframe, Tapi Lebih Baik, dan Lebih Buruk”, Daniel Brain
- “Mengoptimalkan Kinerja”, Bereaksi dokumentasi
- “Manual Pengguna dan Panduan Referensi”, dokumentasi CodeMirror