จัดระเบียบโค้ดด้วย .JSX
JSX ย่อมาจาก ( JavaScript Syntax eXtension) ซึ่งหมายถึงส่วนเสริมของ Javascript นั่นเองครับ ถูกพัฒนาขึ้นมาใช้กับ React โดยเฉพาะ โดย Syntax นั้นมีความคล้ายคลึงกับ HTML เป็นอย่างมาก แต่สิ่งนึงที่เห็นได้ชัดคือจะเห็นการเขียนโค้ดในลักษณะนี้ในอยู่ในไฟล์ Javascript แทนที่จะเป็นไฟล์ HTML และแยกการทำงานเป็นส่วนๆ เรียกว่า คอมโพเนนท์
คอมโพเนนท์
คอมโพเนนท์สามารถอ้างอิงและใช้งานคอมโพเนนท์อื่นๆได้ ซึ่งทำให้เราสามารถใช้งานคอมโพเนนท์ได้ในทุกระดับเช่น ปุ่ม, ฟอร์ม, กล่องข้อความ หรือแม้กระทั่งทั้งหน้าจอ ทุกสิ่งทุกอย่างใน React นั้นถูกแสดงจากคอมโพเนนท์หลายๆ คอมโพเนนท์ร่วมกัน
ข้อกำหนดเบื้องต้น
ข้อกำหนดสำหรับบทความนี้คือ คุณควรได้ทำตามบทความ สร้างภาพสามมิติแบบโต้ตอบ (Interactive) มาก่อน
จัดระเบียบโค้ด แยกเป็นไฟล์ คอมโพเนนท์ .jsx
สร้างโฟลเดอร์ components ภายในโฟลเดอร์ src

สร้างไฟล์ Orbit.jsx
สร้างไฟล์ Orbit.jsx ภายในโฟลเดอร์ components เขียนโค้ดดังนี้
import { extend, useThree } from 'react-three-fiber';
import {
OrbitControls
} from 'three/examples/jsm/controls/OrbitControls';
extend({ OrbitControls });
const Orbit = () => {
const { camera, gl } = useThree();
return (
<orbitControls
attach='orbitControls'
args={[camera, gl.domElement]}
/>
)
}
export default Orbit;

ที่ไฟล์ App.js ลบโค้ดออกดังนี้


เพิ่มโค้ด
import Orbit from './components/Orbit';

สร้างไฟล์ Box.jsx
สร้างไฟล์ Box.jsx ภายในโฟลเดอร์ components
Cut โค้ดส่วนของ Box จากไฟล์ App.js ไปที่ไฟล์ Box.jsx



โค้ด
import { useRef } from 'react';
import { useLoader, useFrame } from 'react-three-fiber';
import * as THREE from 'three';
const Box = props => {
const ref = useRef();
const texture = useLoader(
THREE.TextureLoader,
'/wood.jpg'
);
useFrame(state => {
ref.current.rotation.y += 0.01;
ref.current.rotation.x += 0.01;
});
const handlePointerDown = e => {
console.log(e)
e.object.active = true;
if (window.activeMesh) {
scaleDown(window.activeMesh)
window.activeMesh.active = false;
}
window.activeMesh = e.object
}
const handlePointerEnter = e => {
e.object.scale.x = 1.5
e.object.scale.y = 1.5
e.object.scale.z = 1.5
}
const handlePointerLeave = e => {
if (!e.object.active) {
scaleDown(e.object)
}
}
const scaleDown = object => {
object.scale.x = 1
object.scale.y = 1
object.scale.z = 1
}
return (
<mesh
ref={ref}
{...props}
castShadow
onPointerDown={handlePointerDown}
onPointerEnter={handlePointerEnter}
onPointerLeave={handlePointerLeave}
>
<boxBufferGeometry args={[1, 1, 1]} />
<meshPhysicalMaterial
map={texture}
/>
</mesh>
)
}
export default Box;
เพิ่มโค้ดนำเข้า Box ที่ไฟล์ App.js
import Box from './components/Box';

สร้างไฟล์ Background.jsx
สร้างไฟล์ Background.jsx ภายในโฟลเดอร์ components
Cut โค้ดส่วนของ Background จากไฟล์ App.js ไปที่ไฟล์ Background.jsx


โค้ด
import { useLoader, useThree } from 'react-three-fiber';
import * as THREE from 'three';
const Background = props => {
const texture = useLoader(
THREE.TextureLoader,
'/autoshop.jpg'
);
const { gl } = useThree();
const formatted = new THREE.WebGLCubeRenderTarget(
texture.image.height
).fromEquirectangularTexture(gl, texture)
return (
<primitive
attach='background'
object={formatted}
/>
)
}
export default Background;
เพิ่มโค้ดนำเข้า Background ที่ไฟล์ App.js
import Background from './components/Background';

สร้างไฟล์ Floor.jsx
สร้างไฟล์ Floor.jsx ภายในโฟลเดอร์ components
Cut โค้ดส่วนของ Floor จากไฟล์ App.js ไปที่ไฟล์ Floor.jsx


โค้ด
const Floor = props => {
return (
<mesh {...props} receiveShadow>
<boxBufferGeometry args={[20, 1, 10]} />
<meshPhysicalMaterial
/>
</mesh>
)
}
export default Floor;
เพิ่มโค้ดนำเข้า Floor ที่ไฟล์ App.js
import Floor from './components/Floor';

สร้างไฟล์ Bulb.jsx
สร้างไฟล์ Bulb.jsx ภายในโฟลเดอร์ components
Cut โค้ดส่วนของ Bulb จากไฟล์ App.js ไปที่ไฟล์ Bulb.jsx


โค้ด
const Bulb = props => {
return (
<mesh {...props}>
<pointLight castShadow />
<sphereBufferGeometry args={[0.2, 20, 20]} />
<meshPhongMaterial emissive='yellow' />
</mesh>
)
}
export default Bulb;
เพิ่มโค้ดนำเข้า Bulb ที่ไฟล์ App.js
import Bulb from './components/Bulb';

สร้างฟังก์ชัน ColorPicker
const ColorPicker = props => {
return (
)
}
Cut โค้ดจากฟังก์ชัน App ไปที่ฟังก์ชัน ColorPicker


Cut โค้ดจากฟังก์ชัน App ไปที่ฟังก์ชัน ColorPicker


โค้ด
const ColorPicker = props => {
const handleClick = e => {
if (!window.activeMesh) return;
window.activeMesh.material.color = new THREE.Color(e.target.style.background)
}
return (
<div style={{ position: 'absolute', zIndex: 1 }}>
<div
onClick={handleClick}
style={{
background: 'blue',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'yellow',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'white',
height: 50,
width: 50
}}
></div>
</div>
)
}
เพิ่มโค้ดนำเข้าฟังก์ชัน ColorPicker ที่ฟังก์ชัน App
< ColorPicker />

โค้ดไฟล์ App.js
import './App.css';
import {
Canvas, useFrame
} from 'react-three-fiber';
import { Suspense } from 'react';
import Orbit from './components/Orbit';
import Box from './components/Box';
import Background from './components/Background';
import Floor from './components/Floor';
import Bulb from './components/Bulb';
import * as THREE from 'three'
const ColorPicker = props => {
const handleClick = e => {
if (!window.activeMesh) return;
window.activeMesh.material.color = new THREE.Color(e.target.style.background)
}
return (
<div style={{ position: 'absolute', zIndex: 1 }}>
<div
onClick={handleClick}
style={{
background: 'blue',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'yellow',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'white',
height: 50,
width: 50
}}
></div>
</div>
)
}
function App() {
return (
<div style={{ height: '100vh', width: '100vw' }}>
< ColorPicker />
<Canvas
shadowMap
style={{ background: 'black' }}
camera={{ position: [7, 7, 7] }}
>
<ambientLight intensity={0.2} />
<Bulb position={[0, 3, 0]} />
<Orbit />
<axesHelper args={[5]} />
<Suspense fallback={null}>
<Box position={[-4, 1, 0]} />
</Suspense>
<Suspense fallback={null}>
<Box position={[4, 1, 0]} />
</Suspense>
<Suspense fallback={null}>
<Background />
</Suspense>
<Floor position={[0, -0.5, 0]} />
</Canvas>
</div>
);
}
export default App;
สร้างไฟล์ ColorPicker.jsx
สร้างไฟล์ ColorPicker.jsx ภายในโฟลเดอร์ components
Cut โค้ดส่วนของฟังก์ชัน ColorPicker จากไฟล์ App.js ไปที่ไฟล์ ColorPicker.jsx


โค้ด ไฟล์ ColorPicker.jsx
import * as THREE from 'three';
const ColorPicker = props => {
const handleClick = e => {
if (!window.activeMesh) return;
window.activeMesh.material.color = new THREE.Color(e.target.style.background)
}
return (
<div style={{ position: 'absolute', zIndex: 1 }}>
<div
onClick={handleClick}
style={{
background: 'blue',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'yellow',
height: 50,
width: 50
}}
></div>
<div
onClick={handleClick}
style={{
background: 'white',
height: 50,
width: 50
}}
></div>
</div>
)
}
export default ColorPicker;
เพิ่มโค้ดนำเข้า ColorPicker ที่ไฟล์ App.js
import ColorPicker from './components/ColorPicker';

โค้ด ไฟล์ App.js
import './App.css';
import {
Canvas, useFrame
} from 'react-three-fiber';
import { Suspense } from 'react';
import Orbit from './components/Orbit';
import Box from './components/Box';
import Background from './components/Background';
import Floor from './components/Floor';
import Bulb from './components/Bulb';
import ColorPicker from './components/ColorPicker';
function App() {
return (
<div style={{ height: '100vh', width: '100vw' }}>
< ColorPicker />
<Canvas
shadowMap
style={{ background: 'black' }}
camera={{ position: [7, 7, 7] }}
>
<ambientLight intensity={0.2} />
<Bulb position={[0, 3, 0]} />
<Orbit />
<axesHelper args={[5]} />
<Suspense fallback={null}>
<Box position={[-4, 1, 0]} />
</Suspense>
<Suspense fallback={null}>
<Box position={[4, 1, 0]} />
</Suspense>
<Suspense fallback={null}>
<Background />
</Suspense>
<Floor position={[0, -0.5, 0]} />
</Canvas>
</div>
);
}
export default App;

ดูผ่านเว็บไซต์ได้ที่