Styling in React

หลังจาก React ได้รับความนิยมเพิ่มขึ้นเรื่อยๆ ผมเองก็ถือเป็นหนึ่งในนั้นที่ชอบความโดดเด่นของ React โดยใน medium นี้ก็จะขอพูดไปเรื่อยๆ เกี่ยวกับการกำหนด style ใน React

เกริ่นก่อนเลย React มีการอธิบาย DOM ในรูปแบบของ JavaScript function (component) แทน data (html, ng, knockout or what ever template) ทำให้ในจุดนี้เราสามารถทั้งใช้วิธีการกำหนด style ด้วย inline style หรือจะด้วย css เหมือนกับที่เคยทำในการพัฒนาเว็บ html ปกติได้

กำหนด Style ได้ดีกว่า

แต่ด้วยความที่ React component คือ JavaScript function เลยเกิดการคิดค้นวิธีการกำหนด style จาก JS หรือที่เรียกว่า css in js ซึ่งก็มีหลายค่ายทำออกมา เช่น radium, styled-components, jss เป็นต้น ข้างล่างคือตัวอย่างการกำหนด style จาก JavaScript

import styled from 'styled-components'
const RoundedButton = styled.button`
border: 1px solid ${(props) => props.borderColor};
border-radius: 25px;
`
const Panel = props => (
<div>
<RoundedButton borderColor="blue" />
</div>
)

ตัวอย่างเริ่มต้นด้วยการสร้างปุ่มที่มีกรอบล้อมรอบ มีความโค้งมน และสามารถกำหนดสีของกรอบได้ โดยใน component Panel ได้แสดงวิธีการใช้งานปุ่มนี้ไว้ แน่นอนว่าการทำอะไรที่ dynamic แบบนี้ใน html มีเพียงแค่การ inline style เท่านั้น นอกนั้นการคือการผสม css class ทำงานร่วมกัน

ซึ่งตัวอย่างนี้ได้แสดงให้เห็นว่าการ styling ด้วย js นั้นผลักดันขีดความสามารถในการกำหนด style ออกไปได้มากกว่าเดิม ซึ่งแน่นอนว่าการกำหนดผ่าน template ที่มีแนวทางได้ไม่มากนัก ถึงจะมี tag พิเศษต่างๆ เพิ่มเข้ามา (ในแต่ละ framework ก็อาจจะแตกต่างกันไป) ก็ยังมีข้อจำกัดที่มันเป็นเพียง data มันไม่ใช่ function

Behavior and Style

อีกประเด็นที่อยากจะกล่าวถึงคือการที่เราพยายามแยก javascript กับ css ออกจากกัน มันคงเป็นหลักการที่ดีที่ว่า logic อยู่ส่วน logic ส่วน style ก็อยู่ส่วน style ซึ่งเป็นเรื่องที่ดี แต่ในบางส่วนก็มีจุดที่เหลื่อมล้ำกัน

ยกตัวอย่างเช่น เรามีแอพ Todo list แล้วผมก็ลืมเขียน style ให้กับ css class todo_item_is_completed ว่าจะต้องมีเส้นขีดคาด เมื่อลองใช้ Todo list จะเกิดอะไรขึ้นครับ? แน่นอนว่ากด todo complete ไปแค่ไหนก็คิดว่ามันไม่ทำงานใช่ไหมครับ เพราะเส้นขีดคาดไม่ยอมขึ้นมา คงเพราะ app bug หรืออะไรนะ ทั้งที่จริงๆ ก็แค่ลืม style นี่ไม่ใช่สิ่งที่ดีครับ เพราะการที่เราลืม style มันมาทำร้ายพฤติกรรมการใช้งาน

จากรูปข้างบน นี่ละครับคือ style ที่มีผลกับพฤติกรรม และมันเหมาะสมกว่าที่จะถูกควบคุมด้วย state ภายใน JavaScript เพราะงั้นเราควรเอามันกลับมาที่ฟาก JS เช่น

ก่อน

<li className={classnames({
'todo_item': true,
'todo_item_is_complete': props.isCompleted,
})}>
{props.text}
</li>

หลัง

const style = props.isCompleted ? 
{ textDecoration: 'line-through' } :
undefined;
<li className="todo_item" style={style}>
{props.text}
</li>

ตัวอย่างหลังมีการใช้งาน className คล้ายก่อนหน้า เพิ่มเติมคือย้ายการกำหนด style ที่บ่งบอก state ของ todo มาไว้ใน Component แทน ซึ่งแน่นอนว่าสามารถที่จะใช้ css in js library ทั้งหลายเข้ามาช่วยให้เขียนง่ายขึ้นไปอีก

ยิ่งไปกว่านั้นการเขียนเทสเคสก็จะต่างออกไปด้วย แทนที่จะเขียนเทสเคส โดยที่ตั้งคำถามว่าเราระบุ className ได้ถูกต้องหรือเปล่าเมื่อ state เปลี่ยนไป มาเขียนเทสว่า style ที่เราสนใจเมื่อ state เปลี่ยนไป เป็นไปตามนั้นจริงหรือเปล่า ซึ่งนอกจากจะธรรมชาติกว่าแล้ว ยังได้ผลจริง ไม่เกิดปัญหาที่ผมกล่าวข้างต้น

มาถึงตรงนี้ก็น่าจะได้ไอเดียไปด้วยนะครับว่า style แบบไหนที่ควรนำมาไว้ใน js

Modularity

เนื่องจาก React ถูกออกแบบมาให้สามารถที่จะนำ Component ไปใช้ซ้ำได้ในหลายๆ ที่ในแอพพลิเคชัน การกำหนด style ที่ดีคือ style จะต้องไม่พัง หากนำ component ไปวางไว้ในส่วนอื่นภายใน hierarchy ของ app ไม่เช่นนั้นจะต้องมาแก้ไข style ทุกครั้งที่มีการย้ายหรือใช้ซ้ำ component ซึ่งไม่ใช่สิ่งที่พึงประสงค์แน่นอนสำหรับการพัฒนาซอฟต์แวร์

สิ่งถัดมาที่เรามักจะทำในการเขียน React คือการที่เราสร้าง component ขึ้นมา แล้วก็ สร้าง css class สำหรับ component นั้น เช่น

// Post.js
const Post = props => <div className="post">...</div>
// Post.css
.post { ... }

แล้วเวลาผ่านไป คิดว่าจะชื่อนี่เริ่มจะไม่สื่อความหมายซะแล้ว งั้นเปลี่ยนชื่อ component สิ่งที่ตามมาคือ โอ้ เพื่อให้อนาคตไม่งงว่าทำไม css ชื่อ class มันแปลก ไม่ตรงกับชื่อ component งั้นก็ต้องเปลี่ยนตาม แล้วมันก็ตามหลอกหลอนแบบนี้เรื่อยไป เมื่อสิ่งที่ยึดเหนี่ยว component กับ style ไว้คือแค่ string เปราะบางเท่านั้น

ถ้าย้าย style นั้นเข้ามาใช้ css in js คงไม่เจอปัญหานี้ นั่นซินะ :) ยิ่งไปกว่านั้นก็จะได้ Modularity ที่สมบูรณ์แบบ เพราะการกำหนด style ถูกจับแนบแน่นอยู่กับ component

แต่ผมก็ไม่ได้ชี้ว่า ให้เลิกใช้ css ครับ มันยังคงจำเป็นหากเรา design ได้ดี ยกตัวอย่างเช่นหากใครรู้จักการจัด layout ด้วย css framework ก็คงจะรู้ว่ามันแสนสะดวกมากในการกำหนดความกว้าง ช่องไฟ ในส่วนนี้หากไม่ได้เป็น style ที่จำเพาะเจาะจง component ใดมันจึงเหมาะที่จะ apply ไปทั่วแอพตรงไหนก็ใช้งานมันได้ ซึ่งจะเห็นได้ว่าความละเอียดในการกำหนดการใช้งาน css มีความสำคัญมากซึ่งต้อง design ให้ดี ควรเน้นที่การกำหนดเพื่อ reuse ใช้งานได้หลายที่ มากกว่าเฉพาะเจาะจงใช้กับ component ใดๆ

สุดท้ายนี้ก็ขอให้มี mindset แบบนี้ครับ

STYLE IS NOT CSS

Designer อย่ายึดติดว่าเขียน css เป็นแล้วจะไม่เรียนรู้เพิ่มเติมแล้ว Developer เค้าจะลำบากเอา แฮร่ ~

resources

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.