react  การใช้ style components และการแยก components01 September 2020Programing

react การใช้ style components และการแยก components

ก่อนหน้านี้ตอนที่เราเริ่มเรียน react ใหม่ๆ หน้าหนึ่งจะมีโค้ดที่ใช้เขียน layout ทั้งหน้า รวมอยู่ในไฟล์เดียวกัน ซึ่งว่ากันตามตรงถ้าต้องกลับมาแก้โค้ดจะปวดหัวมากเพราะต้องมาหาว่าส่วนนี้คือตรงไหน โค้ดก็ยาวอีก แถมเมื่อเราเขียน css แล้ว import เข้ามาในไฟล์ react สักหน้าก็โดนเรียกใช้ซ้ำหลายรอบ พอเรียนรู้ไปพักก็ได้มีโอกาสจับโปรเจคที่เขาใช้ react และมีตัวอย่างการแยก components มาให้ดูบ้างถึงเข้าจะไม่ได้เขียนแบบสมบูรณ์ว่า propstype ต้องเป็นค่าอะไร

วันนี้เป็นโอกาสดีที่จะสอนใช้ style components แบบเขียนเป็นธีม และการแยก components เพื่อแก้ปัญหาที่เราพบในตอนที่เราเริ่มเรียน react สำหรับมือใหม่

Create React App

เริ่มต้นด้วยการสร้าง project react ก่อน ด้วยคำสั่ง

วิธีที่ 1 ใช้ npx (npx คือ package runner tool ที่ติดมากับ npm 5.2+ หรือเวอร์ชั่นสูงกว่า)

npx create-react-app react-with-styled-compontents หรือเป็น project-name ของเรา

หรือวิธีที่ 2 เราจะใช้ npm (ถ้าจะใช้ npm แนะนำให้ใช้ npm เวอร์ชั่น 6 ขึ้นไป)

npm init react-app react-with-styled-compontents หรือเป็น project-name ของเรา

สำหรับใครที่ใช้ Yarn (yarn create แนะนำ Yarn 0.25+)

yarn create react-app react-with-styled-compontents หรือเป็น project-name ของเรา

จากนั้นรอสักครู่ เมื่อรันคำสั่ง create react-app เสร็จจะได้หน้า terminal ดังภาพข้างล่าง

react create project

เมื่อสร้าง Project เสร็จแล้วภายในโฟลเดอร์ react-with-styled-compontents จะมีโครงสร้าง แพ็คเกจ และไฟล์เบื้องต้นของ Project ต่างๆไว้เรียบร้อยแล้ว ดังโครงสร้างด้านล่าง

react-with-styled-compontents
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
  • node_modules – โฟลเดอร์นี้จะมี dependencies และ sub-dependencies ของ packages ที่ต้องใช้ภายใน project
  • package.json – ไฟล์สรุปรวมทั้งหมดของการ settings สำหรับ React application
  • public – โฟลเดอร์นี้สำหรับใส่ไฟล์อื่นๆ ที่จะให้เข้าถึงได้โดยตรง
  • src – โฟลเดอร์นี้จะใช้บ่อยสุด เพราะ Components ต่างๆ จะอยู่ที่นี่

จากนั้นทดลองรันหน้าเว็บด้วยคำสั่ง

cd react-with-styled-compontents หรือ cd project-name
npm start หรือ yarn start

create components

หลังจากเราสร้าง project เสร็จแล้วเรามาสร้างโฟลเดอร์ pages และ components เพื่อใช้สำหรับเขียน components และแยกการเขียน style components ให้ดูง่ายกันดังนี้

template html breed2 to react

ใช้เทมเพลตตัวอย่างจากเว็บ https://colorlib.com/wp/template/breed2/

  • commons เก็บ components ที่ใช้ซ้ำอาจจะใช้เป็นชื่ออื่นก็ได้
  • pages เก็บหน้าเว็บที่สร้าง
└── src
    └── components
        └── commons
            └── Layout
                ├── style.js
                └── index.js
        └── pages
            └── pages
                └── About
                    ├── About.js
                    ├── style.js
                    └── index.js
                ├── App.js
                └── index.js

ลง package reactstrap เพื่อใช้ components ของ reactstrap

yarn add reactstrap bootstrap

Import Bootstrap CSS ลงในไฟล์ src/index.js

import "bootstrap/dist/css/bootstrap.min.css";

และลง package react-router สำหรับใช้งานเรียกหน้าเรียกเพจใหม่

yarn add react-router-dom react-router

สำหรับใครจะใช้ไอคอนเราใช้ paackage react-icons

yarn add react-icons

มาเข้าสู่ขั้นตอนการใช้ style-components กัน

แยก Header Layout และ Footer ออกมาเป็น components ที่โฟลเดอร์ src/components/commons

// src/components/commons/Header/index.js

import React, { useState } from "react";
import {
  Collapse,
  Navbar,
  NavbarToggler,
  NavbarBrand,
  Nav,
  NavItem,
  NavLink,
  UncontrolledDropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
} from "reactstrap";

const Header = (props) => {
  const pathname = window.location.pathname;
  const [isOpen, setIsOpen] = useState(false);

  const toggle = () => setIsOpen(!isOpen);
  return (
    <header className="header_area header_inner_page">
      <div className="main_menu">
        <nav className="navbar navbar-expand-lg navbar-light">
          <div className="container">
            <Navbar expand="lg">
              <NavbarBrand href="/" className="navbar-brand logo_h">
                <img src="assets/images/logo.png" alt="" />
              </NavbarBrand>
              <NavbarBrand href="/" className="navbar-brand logo_inner_page">
                <img src="assets/images/logo2.png" alt="" />
              </NavbarBrand>
              <NavbarToggler onClick={toggle} />
              <Collapse isOpen={isOpen} navbar>
                <Nav className="mr-auto" navbar>
                  <NavItem active={pathname === "/" ? true : false}>
                    <NavLink href="/">Home</NavLink>
                  </NavItem>
                  <NavItem active={pathname === "/about" ? true : false}>
                    <NavLink href="/about">About</NavLink>
                  </NavItem>
                  <NavItem active={pathname === "/portfolio" ? true : false}>
                    <NavLink href="/portfolio">Portfolio</NavLink>
                  </NavItem>
                  <UncontrolledDropdown nav inNavbar>
                    <DropdownToggle nav caret>
                      Pages
                    </DropdownToggle>
                    <DropdownMenu right>
                      <DropdownItem>Services</DropdownItem>
                      <DropdownItem>Portfolio Details</DropdownItem>
                    </DropdownMenu>
                  </UncontrolledDropdown>
                  <UncontrolledDropdown nav inNavbar>
                    <DropdownToggle nav caret>
                      Blog
                    </DropdownToggle>
                    <DropdownMenu right>
                      <DropdownItem>Blog</DropdownItem>
                      <DropdownItem>Blog Details</DropdownItem>
                    </DropdownMenu>
                  </UncontrolledDropdown>
                  <NavItem active={pathname === "/contact" ? true : false}>
                    <NavLink href="/contact">Contact</NavLink>
                  </NavItem>
                </Nav>
              </Collapse>
            </Navbar>
          </div>
        </nav>
      </div>
    </header>
  );
};

export default Header;
// src/components/commons/Footer/index.js

import React from "react";
import { Link } from "react-router-dom";
import { Nav, NavItem, NavLink } from "reactstrap";
import {
  FaFacebookF,
  FaTwitter,
  FaSkype,
  FaPinterestP,
  FaHeart,
} from "react-icons/fa";

const index = () => {
  return (
    <footer className="footer_area">
      <div className="container">
        <div className="row justify-content-center">
          <div className="col-lg-12">
            <div className="footer_top flex-column">
              <div className="footer_logo">
                <Link to="/">
                  <img src="assets/images/logo2.png" alt="" />
                </Link>
                <div className="d-lg-block d-none">
                  <nav className="navbar navbar-expand-lg navbar-light justify-content-center">
                    <div className="collapse navbar-collapse offset">
                      <Nav className="nav navbar-nav menu_nav mx-auto">
                        <NavItem>
                          <NavLink className="text-white" href="#">
                            Home
                          </NavLink>
                        </NavItem>
                        <NavItem>
                          <NavLink className="text-white" href="#">
                            About
                          </NavLink>
                        </NavItem>
                        <NavItem>
                          <NavLink className="text-white" href="#">
                            Portfolio
                          </NavLink>
                        </NavItem>
                        <NavItem>
                          <NavLink className="text-white" href="#">
                            BLog
                          </NavLink>
                        </NavItem>
                        <NavItem>
                          <NavLink className="text-white" href="#">
                            Services
                          </NavLink>
                        </NavItem>
                      </Nav>
                    </div>
                  </nav>
                </div>
              </div>
              <div className="footer_social mt-lg-0 mt-4">
                <Link to="/">
                  <FaFacebookF />
                </Link>
                <Link to="/">
                  <FaTwitter />
                </Link>
                <Link to="/">
                  <FaSkype />
                </Link>
                <Link to="/">
                  <FaPinterestP />
                </Link>
              </div>
            </div>
          </div>
        </div>
        <div className="row footer_bottom justify-content-center">
          <p className="col-lg-8 col-sm-12 footer-text">
            {`Copyright © ${new Date().getFullYear()}
            All rights reserved | This template is made with `}
            <FaHeart /> by
            <Link to="https://colorlib.com">Colorlib</Link>
          </p>
        </div>
      </div>
    </footer>
  );
};

export default index;
// src/components/commons/Layout/index.js

import React from "react";
import Header from "../Header";
import Footer from "../Footer";

const Layout = (props) => {
  return (
    <>
      <Header />
      {props.children}
      <Footer />
    </>
  );
};

export default Layout;

สร้างไฟล์ aboutไว้ที่ src/components/pages

// src/components/pages/About/About.js

import React, { Component } from "react";
import Layout from "../../commons/Layout";
import { Link } from "react-router-dom";

class About extends Component {
  render() {
    return (
      <Layout>
        {/* Start Banner Area */}
        <section className="banner_area">
          <div className="banner_inner d-flex align-items-center">
            <div className="container">
              <div className="banner_content text-center">
                <h2>About Us</h2>
                <div className="page_link">
                  <Link to="/">Home</Link>
                  <Link to="/about">About</Link>
                </div>
              </div>
            </div>
          </div>
        </section>
        {/* End Banner Area */}
        {/* Start About Us Area */}
        <section className="about_area section_gap">
          <div className="container">
            <div className="row justify-content-start align-items-center">
              <div className="col-lg-5">
                <div className="about_img">
                  <img className="" src="images/about-us.png" alt="" />
                </div>
              </div>

              <div className="offset-lg-1 col-lg-5">
                <div className="main_title text-left">
                  <p className="top_text">
                    About me <span></span>
                  </p>
                  <h2>
                    Creative Art Director <br />
                    And Designer
                  </h2>
                  <p>
                    Also signs his face were digns fish don't first isn't over
                    evening hath divided days light darkness gathering moved dry
                    all darkness then fourth can't create d forth Also signs
                    Also signs his face were moltenus Also signs his face
                  </p>
                  <button className="primary_btn">Download CV</button>
                </div>
              </div>
            </div>
          </div>
        </section>
        {/* End About Us Area */}
        {/* Start Testimonial Area */}
        <section className="testimonial_area pb-xl-300px">
          <div className="container">
            <div className="row">
              <div className="col-lg-12">
                `
                <div className="main_title">
                  <p className="top_text">
                    Our Tesitmonial <span></span>
                  </p>
                  <h2>
                    Honourable Client Says <br />
                    About Me
                  </h2>
                </div>
              </div>
            </div>

            <div className="owl-carousel owl-theme testimonial-slider ">
              <div className="testimonial-item">
                <div className="row">
                  <div className="col-lg-6">
                    <div className="testi-img mb-4 mb-lg-0">
                      <img src="images/testimonials/testimonial1.png" alt="" />
                    </div>
                  </div>
                  <div className="col-lg-6">
                    <div className="testi-right">
                      <h4>Roser Henrique</h4>
                      <p>
                        <small>Project Manager, Apple</small>
                      </p>

                      <p>
                        Waters can not replenish hath fly and be to brought
                        isn't very days behold without land every above lights
                        us fruitful wherein divide it him fowl moving may
                        beginning subdue fly waters can't replenish hath fly and
                        be to brought isn't very days behold
                      </p>
                      <ul className="star_rating mt-4">
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li className="disable">
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>

              <div className="testimonial-item">
                <div className="row">
                  <div className="col-lg-6">
                    <div className="testi-img mb-4 mb-lg-0">
                      <img src="images/testimonials/testimonial1.png" alt="" />
                    </div>
                  </div>
                  <div className="col-lg-6">
                    <div className="testi-right">
                      <h4>Roser Henrique</h4>
                      <p>
                        <small>Project Manager, Apple</small>
                      </p>

                      <p>
                        Waters can not replenish hath fly and be to brought
                        isn't very days behold without land every above lights
                        us fruitful wherein divide it him fowl moving may
                        beginning subdue fly waters can't replenish hath fly and
                        be to brought isn't very days behold
                      </p>
                      <ul className="star_rating mt-3">
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li className="disable">
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>

              <div className="testimonial-item">
                <div className="row">
                  <div className="col-lg-6">
                    <div className="testi-img mb-4 mb-lg-0">
                      <img src="images/testimonials/testimonial1.png" alt="" />
                    </div>
                  </div>
                  <div className="col-lg-6">
                    <div className="testi-right">
                      <h4>Roser Henrique</h4>
                      <p>
                        <small>Project Manager, Apple</small>
                      </p>

                      <p>
                        Waters can not replenish hath fly and be to brought
                        isn't very days behold without land every above lights
                        us fruitful wherein divide it him fowl moving may
                        beginning subdue fly waters can't replenish hath fly and
                        be to brought isn't very days behold
                      </p>
                      <ul className="star_rating mt-3">
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li>
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                        <li className="disable">
                          <span>
                            <i className="fas fa-star"></i>
                          </span>
                        </li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
        {/* End Testimonial Area */}
        {/* Start Brands Area */}
        <section className="brands-area section_gap_bottom">
          <div className="container">
            <div className="row justify-content-center">
              <div className="col-lg-12">
                <div className="owl-carousel brand-carousel">
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo1.png" alt="" />
                    </div>
                  </div>
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo2.png" alt="" />
                    </div>
                  </div>
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo3.png" alt="" />
                    </div>
                  </div>
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo4.png" alt="" />
                    </div>
                  </div>
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo5.png" alt="" />
                    </div>
                  </div>
                  {/* single-brand */}
                  <div className="single-brand-item d-table">
                    <div className="d-table-cell">
                      <img src="images/brands/logo3.png" alt="" />
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
        {/* End Brands Area */}
      </Layout>
    );
  }
}

export default About;
// src/components/pages/About/index.js

export { default as About } from "./About";

และสร้างไฟล์ index.js

export { About } from "./About";

และแก้ไฟล์ App.js

import React, { Component } from "react";
import { About } from "./components/pages";
import { Switch, Route, BrowserRouter as Router } from "react-router-dom";

export const Routes = {
  about: "/about",
};

class App extends Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route path={Routes.about} component={About} />
        </Switch>
      </Router>
    );
  }
}

export default App;

หน้าเว็บที่ได้ก็จะได้ประมาณนี้ เนื่องจากเรายังไม่ได้ใส่ style อะไรภาพที่ก็จะยังไม่ตรงแบบจะได้แค่การจัด layout ตามดีไซน์เท่านั้นซึ่งมาจาก css คลาสของ bootstrap อย่างเดียว

react template breed2 with bootstrap layout before add style

install styled-components

ก่อนอื่นลง package styled-components ด้วยคำสั่ง

npm install --save styled-components

หรือ

yarn add styled-components

Import ThemeProvider ลงในไฟล์ src/index.js

import { ThemeProvider } from "styled-components";

ประกาศตัวแปรสำหรับใส่ค่าสีธีมลงใน src/index.js เช่น

const theme = {
  primary: "#0c7973",
  secondary: "#6c757d",
  success: "#28a745",
  danger: "#dc3545",
  warning: "#ffc107",
  info: "#17a2b8",
  light: "#f8f9fa",
  dark: "#343a40",
  textnormal: "#212529",
  white: "#FFFFFF",
  gray: "#d9d9d9",
  muted: "#6c757d",
};

จากนั้นไปที่ ReactDOM.render เพิ่ม tag <ThemeProvider> ลงไป

ReactDOM.render(
  <ThemeProvider theme={theme}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ThemeProvider>,
  document.getElementById("root")
);

สร้าง components Button เพื่อแยกปุ่มออกมาเพราะปุ่มสามารถนำไปใช้ได้หลายหน้า

// src/components/commons/ButtonCV/index.js

import React from "react";
import { Button } from "reactstrap";

const ButtonCV = ({ onClick, btnTxt }) => {
  return (
    <Button className="primary_btn" onClick={onClick}>
      {btnTxt}
    </Button>
  );
};

export default ButtonCV;

เราสามารถใส่ sstyled-components ลงไปในไฟล์ `src/components/commons/Button/index.js` ได้เลย

import React from "react";
import styled from "styled-components";
import { Button } from "reactstrap";

export const ButtonStyle = styled(Button)`
  background: ${(props) => props.theme.primary};
  color: #ffffff;
  border: 2px solid ${(props) => props.theme.primary};
  &.primary_btn {
    border: 0;
    display: inline-block;
    background: linear-gradient(
      to right,
      #1345e6 0%,
      #ed239f 51%,
      #1345e6 100%
    );
    color: #fff;
    letter-spacing: 0px;
    font-family: "Roboto", sans-serif;
    font-weight: 500;
    font-size: 14px;
    line-height: 50px;
    padding: 0 38px;
    outline: none !important;
    text-align: center;
    cursor: pointer;
    text-transform: uppercase;
    border-radius: 5px;
    background-size: 200% auto;
    &:hover {
      background-position: right center;
      color: #fff;
    }
  }
`;


const ButtonCV = ({ className, onClick, btnTxt }) => {
  return (
    <ButtonStyle className={className} onClick={onClick}>
      {btnTxt}
    </ButtonStyle>
  );
};

export default ButtonCV;

โดยจะแก้ Button เป็น ButtonStyle เพื่อเรียกใช้ style จาก styled-components

หรือเราจแยก styled-components มาไว้อีกไฟล์ก็ได้เพื่อนไม่ให้โค้ดส่วนนี้ยาวเกินไปและดูง่ายขึ้น

import styled from "styled-components";
import { Button } from "reactstrap";

export const ButtonStyle = styled(Button)`
  &.primary_btn {
    border: 0;
    display: inline-block;
    background: linear-gradient(
      to right,
      #1345e6 0%,
      #ed239f 51%,
      #1345e6 100%
    );
    color: #fff;
    letter-spacing: 0px;
    font-family: "Roboto", sans-serif;
    font-weight: 500;
    font-size: 14px;
    line-height: 50px;
    padding: 0 38px;
    outline: none !important;
    text-align: center;
    cursor: pointer;
    text-transform: uppercase;
    border-radius: 5px;
    background-size: 200% auto;
    &:hover {
      background-position: right center;
      color: #fff;
    }
  }
`;

ส่วนไฟล์ src/components/commons/ButtonCV/index.js ก็ใช้การ import style เข้ามาใช้แทน

import React from "react";
import { ButtonStyle } from "./style";

const ButtonCV = ({ className, onClick, btnTxt }) => {
  return (
    <ButtonStyle className={className} onClick={onClick}>
      {btnTxt}
    </ButtonStyle>
  );
};

export default ButtonCV;

และเราก็เข้าไปแก้ button ใน src/components/pages/About/index.js

import ButtonCV from "../../commons/ButtonCV";

และก็แทน <button className="primary_btn">Download CV</button> ด้วยโค้ด

<Button btnTxt="Download CV" />

เว็บที่ได้ก็จะเป็นดังภาพ โดยสีที่ได้มาจาก theme ที่เราตั้งค่าสีไว้ใน src/index.js

react with button components
${(props) => props.theme.primary};
ค่า props นี้มาจาก src/index.js ตัวแปร theme ที่ตั้งไว้

แต่ถ้าเราใส่ className ลงไปสีที่ได้ก็เปลี่ยนตามที่เราเพิ่มไว้ เช่น

<ButtonCV className="primary_btn" btnTxt="Download CV" />

จะได้สีตามที่เราเพิ่มไว้ใน const ButtonStyle = styled(Button) ดังภาพ

react button components props classname

ตัว styled components ยังไม่รองรับ linear-gradient ถ้าใครจะใช้แนะนำให้ใส่เป็น class ไปก่อน

จากนั้นเรามาแยก components ส่วน title page

template html breed2 title page

โค้ดจากในไฟล์ template

template html breed2 code title page

สร้างโฟลเดอร์ HeadPage ใน src/components/commons สร้างไฟล์ index.js และ style.js ขึ้นมา คัดลอกโค้ดจากไฟล์ html ส่วน Banner Area มาวาง

import React from "react";

const HeadPage = () => {
  return (
    <section class="banner_area">
      <div class="banner_inner d-flex align-items-center">
        <div class="container">
          <div class="banner_content text-center">
            <h2>About Us</h2>
            <div class="page_link">
              <a href="index.html">Home</a>
              <a href="about.html">About</a>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
};

export default HeadPage;

ไปที่ไฟล์ style.js เพิ่ม import styled from "styled-components"; ไว้บนสุด

ประกาศตัวแปรพร้อม export ค่าออกไป ดังตัวอย่าง export const HeadPageStyle

export const HeadPageStyle = styled.section``; // กรณีที่เราใช้ element html ธรรมดา

export const HeadPageStyle = styled(Button)``; // กรณีที่เราใช้ components ของ package อื่น*

*โดยเราต้องไม่ลืม import components นั้นเข้ามาในไฟล์ style.js ของเราด้วย

จากนั้นก็นำโค้ด scss มาวางได้เลย

import styled from "styled-components";

export const HeadPageStyle = styled.section`
  &.banner_area {
    position: relative;
    z-index: 1;
    @media (max-width: 1199px) {
      min-height: 350px;
    }
    .banner_inner {
      position: relative;
      overflow: hidden;
      width: 100%;
      min-height: 450px;
      background-size: cover;
      z-index: 1;
      background: url("https://colorlib.com/preview/theme/breed2/img/banner/common-banner.png")
        no-repeat right bottom;
      @media (max-width: 1199px) {
        min-height: 350px;
      }
      .banner_content {
        margin-left: 50px;
        margin-top: 40px;
        @media (max-width: 991px) {
          margin-left: 0px;
        }
        h2 {
          color: #fff;
          font-size: 45px;
          font-family: "Roboto", sans-serif;
          margin-bottom: 10px;
          text-transform: uppercase;
          font-weight: 700;
          @media (max-width: 991px) {
            font-size: 30px;
          }
        }
        .page_link {
          a {
            font-size: 12px;
            text-transform: uppercase;
            color: #fff;
            font-family: "Roboto", sans-serif;
            padding-left: 20px;
            padding-right: 8px;
            position: relative;
            display: inline-block;
            &:before {
              font-style: normal;
              font-weight: normal;
              font-variant: normal;
              text-transform: none;
              line-height: 1;
              -webkit-font-smoothing: antialiased;
              content: ">";
              position: absolute;
              right: -10px;
              top: 50%;
              transform: translateY(-50%);
            }
            &:last-child {
              margin-right: 0px;
              &:before {
                display: none;
              }
            }
          }
        }
      }
    }
  }
`;

เสร็จเราก็กลับไปแก้ไฟล์ index.js โดยการ import HeadPageStyle เข้าไป

import { HeadPageStyle } from "./style";

เมื่อกี้เราใช้ styled.section ให้วาง <HeadPageStyle></HeadPageStyle> แทน tag <section></section>

import React from "react";
import { HeadPageStyle } from "./style";

const HeadPage = () => {
  return (
    <HeadPageStyle className="banner_area">
      <div className="banner_inner d-flex align-items-center">
        <div className="container">
          <div className="banner_content text-center">
            <h2>About Us</h2>
            <div class="page_link">
              <a href="index.html">Home</a>
              <a href="about.html">About</a>
            </div>
          </div>
        </div>
      </div>
    </HeadPageStyle>
  );
};

export default HeadPage;

ไปที่ src/components/pages/About/About.js ทำการ import HeadPage มาใช้แทนโค้เดิม

import React, { Component } from "react";
import Layout from "../../commons/Layout";
import HeadPage from "../../commons/HeadPage";

class About extends Component {
  render() {
    
    return (
      <Layout>
        <HeadPage />
.
.
.

ก็จะได้ส่วน title ของหน้าเหมือนเดิมแล้ว

template html breed2 title page by react components

เสร็จแล้วเรามาแยก components ส่วนที่ 2 กัน

เราจะแยก title ที่แสดงคำว่า about me กับ tilte ที่เป็นตัวใหญ่ ก่อนเพราะว่า section ถัดไปใช้

import React from "react";
import { TopTextStyle } from "./style";

const TopText = ({ title }) => {
  return (
    <TopTextStyle className="top_text">
      {title} <span></span>
    </TopTextStyle>
  );
};

export default TopText;
import styled from "styled-components";

export const TopTextStyle = styled.p`
  text-transform: uppercase;
  letter-spacing: 2px;
  font-weight: 500;
  position: relative;
  margin-bottom: 10px;
  span {
    position: relative;
    top: -2px;
    display: inline-block;
    margin-left: 5px;
    width: 80px;
    height: 4px;
    background: rgba(237, 35, 159, 0.6);
    filter: blur(4px);
    border-radius: 5px;
  }
`;
import React from "react";
import TopText from "../TopText";
import Button from "../Button";
import { MainTitleStyle } from "./style";

const MainTitle = ({
  className,
  toptitle,
  title,
  subtitle,
  desc,
  hasButton,
  btnClass,
  btnTxt,
  onClick,
}) => {
  return (
    <MainTitleStyle className={className}>
      <TopText title={toptitle} />
      <div className="main_title text-left">
        <h2>
          {title} <br />
          {subtitle}
        </h2>
        <p>{desc}</p>
        {hasButton === true ? (
          <Button className={btnClass} btnTxt={btnTxt} onClick={onClick} />
        ) : (
          ""
        )}
      </div>
    </MainTitleStyle>
  );
};

export default MainTitle;
import styled from "styled-components";

export const MainTitleStyle = styled.div`
  margin-bottom: 80px;
  @media (max-width: 1199px) {
    margin-bottom: 40px;
  }
  p.top_text {
    text-transform: uppercase;
    letter-spacing: 2px;
    font-weight: 500;
    position: relative;
    margin-bottom: 10px;
    span {
      position: relative;
      top: -2px;
      display: inline-block;
      margin-left: 5px;
      width: 80px;
      height: 4px;
      background: rgba($primary-color2, 0.6);
      @include filter(blur(4px));
      border-radius: 5px;
    }
  }
  h2 {
    font-size: 42px;
    font-weight: 700;
    margin-bottom: 0px;
    line-height: 52px;
    text-transform: capitalize;
    @media (max-width: 767px) {
      font-size: 30px;
      line-height: 34px;
    }
    br {
      @media (max-width: 991px) {
        display: none;
      }
    }
  }
`;

จากนั้นสร้างโฟลเดอร์ SectionGap ที่ src/components/commons เพื่อเก็บไฟล์ section ของ about_area

section about area
import React from "react";
import PropTypes from "prop-types";
import MainTitle from "../MainTitle";
import { SectionGapStyle } from "./style";

const SectionGap = ({
  className,
  titleClass,
  toptitle,
  title,
  subtitle,
  desc,
  hasButton,
  btnClass,
  btnTxt,
  onClick,
  imgSrc,
  imgTitle,
}) => {
  return (
    <SectionGapStyle className={className}>
      <div className="container">
        <div className="row justify-content-start align-items-center">
          <div className="col-lg-5">
            <div className="about_img">
              <img src={imgSrc} alt={imgTitle} />
            </div>
          </div>

          <div className="offset-lg-1 col-lg-5">
            <MainTitle
              className={titleClass}
              toptitle={toptitle}
              title={title}
              subtitle={subtitle}
              desc={desc}
              hasButton={hasButton}
              btnClass={btnClass}
              btnTxt={btnTxt}
              onClick={onClick}
            />
          </div>
        </div>
      </div>
    </SectionGapStyle>
  );
};

SectionGap.propTypes = {
  className: PropTypes.string,
  titleClass: PropTypes.string,
  toptitle: PropTypes.string,
  title: PropTypes.string,
  subtitle: PropTypes.string,
  desc: PropTypes.string,
  hasButton: PropTypes.bool,
  btnClass: PropTypes.string,
  btnTxt: PropTypes.string,
  imgSrc: PropTypes.string,
  imgTitle: PropTypes.string,
  onClick: PropTypes.func,
};
SectionGap.defaultProps = {
  className: "",
};
export default SectionGap;
import styled from "styled-components";

export const SectionGapStyle = styled.section`
  padding: 140px 0;
  @media (max-width: 1199px) {
    padding: 80px 0;
  }
  .about_img {
    position: relative;
    right: 220px;
  }

  .section_gap_top {
    padding-top: 140px;
    @media (max-width: 1199px) {
      padding-top: 80px;
    }
  }

  .section_gap_bottom {
    padding-bottom: 140px;
    @media (max-width: 1199px) {
      padding-bottom: 80px;
    }
  }
`;

เสร็จแล้วไปแก้ไฟล์ About.js

<SectionGap
          className="about_area"
          titleClass="text-left"
          toptitle="About me"
          title="Creative Art Director"
          subtitle="And Designer"
          desc="Also signs his face were digns fish don't first isn't over evening hath divided days light darkness gathering moved dry all darkness then fourth can't create d forth Also signs Also signs his face were moltenus Also signs his face"
          imgSrc="assets/img/about-us.png"
          imgTitle=""
          hasButton={true}
          btnClass="primary_btn"
          btnTxt="Download CV"
          // onClick={}
        />

แทนโค้ดเดิม

section about area
yarn add prop-types

ลง prop-types ไว้สำหรับบังคับค่าที่ถูก props เข้ามา ถ้าหากไม่ใส่ค่าที่ถูกส่งมาจะเป็นอะไรก็ตามก็จะแสดงออกมาแบบนั้น บางครั้งอาจจะ error ได้ถ้าค่าถูก props เข้าไปแปะในส่วนที่ไม่ถูกต้อง

ComponentsName.propTypes

Proptypes อื่นเพิ่มเติมที่ https://reactjs.org/docs/typechecking-with-proptypes.html

จะได้ section About ดังภาพ

section about view

การใช้ styled-components ทำให้เราสะดวกในการ custom style ของ components นั้นๆ ยิ่งในงานกับ components ที่เราแยกออกมาสำหรับ components ที่ใช้ซ้ำๆมาทำเป็น components จะยิ่งทำให้เราลดเวลาการสร้าง components หรือ section เดิมโค้ดแบบเดิมซ้ำๆลงได้

แต่ก็ยังมีจุดที่เราใช้งานไม่ได้ถ้าหน้านั้นใช้ modal แล้ว modal นั้นถูกเรียกในหน้าก็จริงถึงจะถูกคลุมด้วย style ของหน้านั้นก็ไม่สามารถ custom style ลงไปได้เพราะ modal ส่วนใหญ่จะเขียนอยู่ข้างนอก ถัดจาก body เลยทำให้แก้ไข style ส่วนนี้ไม่ได้จึงยังต้องมีการเขียน style ไว้เรียกในหน้า src/index.js หรือ src/App.js อยู่

อ้างอิง

โค้ดตัวอย่าง

ปล. ไม่ได้ตัดหมดทุก components จะมีโค้ดแค่ที่สอนให้ดูเป็นตัวอย่างสำหรับคนที่สนใจอยากลองเอาไปตัด componets เอง

ก่อนหน้า
ถัดไป