--- robots: noindex, nofollow tags: React --- # 在 ASP.NET MVC 專案中新增一個 React 元件 接下來我們會示範怎麼在現有的 ASP.NET MVC 專案中,新增一個元件。 ## 準備 先啟動 Storybook ,並在 `Frontend/src/stories/` 資料夾新增一個和新元件相關的 `.stories.tsx` 檔,例如: ```typescript= import React from 'react'; // also exported from '@storybook/react' if you can deal with breaking changes in 6.1 import { Story, Meta } from '@storybook/react/types-6-0'; import { SettingBlock } from '../components'; export default { title: 'CRM/SettingBlock', component: SettingBlock, argTypes: {}, } as Meta; const Template: Story = (args) => <SettingBlock {...args} />; export const Default = Template.bind({}); ``` 一開始我們從簡就好,想知道怎麼寫 Storybook Controls ,可以看看[官方教學頁面][storybook-controls]。 同時在 `Frontend/src/components/` 內,新增對應的 `.tsx` 檔: ```typescript= // SettingBlock.tsx import styled from 'styled-components'; export const SettingBlock = () => { return ( <div>新元件</div> ); }; ``` 接著切回 `Frontend/` 、啟動 Storybook ,看看元件有沒有出現在左方選單: ```shell= yarn storybook ``` ## 實作 填上元件的肉: ```typescript= import styled from 'styled-components'; import urlComputerIcon from 'images/Computer-icon.png'; const Outer = styled.div` float: left; box-sizing: border-box; `; const Block = styled.div` position: relative; padding: 0 0 0 52px; box-sizing: border-box; padding-bottom: 20px; height: 160px; padding-right: 15px; img { position: absolute; top: -5px; left: 10px; } `; const Header = styled.div` font-size: 100%; line-height: 150%; `; const Title = styled.span` font-size: 18px; display: inline-block; width: 100%; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; `; const MenuItem = styled.li` display: inline-block; font-size: 14px; line-height: 18px; `; const Menu = styled.ul` list-style: none; border: 0; padding: 0; margin: 2px; ${MenuItem} + ${MenuItem}:before { content: "\\a0|\\a0"; } `; const Link = styled.a` color: #92250a; text-decoration: none; `; export const SettingBlock = () => { return ( <Outer> <Block> <Header> <img src={urlComputerIcon} /> <Title>系統</Title> </Header> <Menu> <MenuItem> <Link href="#">服務資訊</Link> </MenuItem> <MenuItem> <Link href="#">系統設定</Link> </MenuItem> <MenuItem> <Link href="#">佈告欄</Link> </MenuItem> <MenuItem> <Link href="#">事件檢視</Link> </MenuItem> <MenuItem> <Link href="#">刪除過時資料</Link> </MenuItem> <MenuItem> <Link href="#">清除資料</Link> </MenuItem> </Menu> </Block> </Outer> ); }; ``` 看看 Storybook 有沒有自動更新畫面,反映您的修改。 ## 整合 找到 `Frontend/src/index.ts` ,手動暴露新元件到 `global` 下,讓 ReactJS.NET 找得到它: ```typescript= import { SettingBlock } from './components'; // 可能的話,只讓 `any` 出現在這個檔案中 (global as any).SettingBlock = SettingBlock; ``` 跑前端開發 script : ```shell= yarn start ``` 它會跑 `webpack --config ./webpack.config.js --watch` ,把打包後的 `*.bundle.js` 放到事先設定好的資料夾中,並監測檔案變化。 打開 Visual Studio ,開啟專案,選擇 `Debug > Debug` ,待瀏覽器開啟後,到已經設定好 ReactJS.NET 的頁面,開啟 devtools ,輸入: ```javascript= window.SettingBlock; ``` 如果看到: ```javascript= f SettingBlock() { return /*#__PURE__*/React.createElement( // 後略... ``` 表示該元件已經成功暴露出來。 接著打開對應的 `.cshtml` ,在想要繪製該 React 元件的地方,寫下: ```csharp= @Html.React("SettingBlock", new {}) ``` 如果有從 view model 暴露出一些資料,則寫成: ```csharp= @Html.React("SettingBlock", new { someProp = Model.someProp }) ``` 最後重新整理頁面,順利的話,就會看到新元件繪製在畫面上。 ## 檢查 在 React 或其他前端 library/framework 文章中,會把 server-side rendering React component 這件事情稱為 dehydrate (脫水)。 除了讓搜尋引擎改善 SEO 外,也能讓禁用 JavaScript 的瀏覽器,至少還能看到該元件第一次繪製出來的樣子。 並把讓這些 DOM element 靠 js 動起來這件事,稱為 hydrate (注水)。 接下來我們要檢查看看這段有沒有成功接起來。 對瀏覽器頁面按右鍵,選擇 `檢視網頁原始碼` ,來看看沒有被 js 修改過的 HTML ,順利的話,會在 `<head>` 或 `<body>` 裡看到: ```html= <style data-styled="true" data-styled-versions="5.1.1"> /* 一大堆 CSS */ </style> ``` 表示成功生成了 styled-components 樣式。 並在想繪製 React 元件的地方,看到: ```html= <div id="react_0HM6VG98HBCF2"<div class="sc_AxjAm kNmqRE"> <!-- 元件內容 --> </div> ``` 表示成功 SSR 了 React 元件。 最後操作一下該元件,來確定 React 有沒有成功把 JavaScript 和這些 DOM element 連接起來。 ## 發佈 如果 repo 決定將 bundle (打包)好的 js 納入版控,那最後還得在 `Frontend/` 下執行: ```shell= yarn build ``` 來生成 `*.bundle.js` 至對應的目錄下。 否則讓 CI/CD 來做這件事即可。 [storybook-controls]: https://storybook.js.org/docs/react/essentials/controls