iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
0
Modern Web

React.js & Laravel 30天訓練系列 第 4

【Day 4】The Detail Structure Of My React.js Project

其實這好像才是昨天的主題,但是我好像太急著要說坑的部分,所以就忘了先仔細介紹我專案的架構

當然,我還沒有完全移除 example的部分,也就是我下載回來改的 Redux & Material UI 的 Template

但是我已經有先把架構都列出來了 給大家參考看看

先附上範例他原本的 src資料夾架構
https://ithelp.ithome.com.tw/upload/images/20171222/20107767KNCnflHc4e.png

然後是我整理之後的
https://ithelp.ithome.com.tw/upload/images/20171222/20107767JoK8sjTxXp.png

我們一一來介紹一下放了什麼東西

  • components
    我們拿來放Component的地方,但是每個component我會用資料夾在包一層,因為我用jsx來寫,所以最後都會將他export出來,然後再用資料夾底下的index.js直接送出去,所以當我在import相關的component時,我只要到資料夾那一層就可以了,如下圖
    component 資料夾結構 /component類別/ include component類別.jsx & indes.js
    https://ithelp.ithome.com.tw/upload/images/20171222/20107767HRqHSAEg9G.png

component.jsx的長相
https://ithelp.ithome.com.tw/upload/images/20171222/20107767s1dXztoS29.png

index.js的長相
https://ithelp.ithome.com.tw/upload/images/20171222/20107767DfN4WKfHxD.png

最後 像我如果要用這一個component的話
就只要 import LoginPage_CP from '../../components/LoginPage'

  • containers
    簡單說 containers 裡面就是存放跟Redux很有關聯的東西,就我的理解是這樣的
    Component 如果你想要去更新 或讀取state 就是要有人把你連起來 其實這概念跟 AngularJs & Angular2 的service 監視動作很像.
    所以,container就是一個大的組合器 她把Redux Action Store Component 集合起來 最後讓你的component 讀取state 操作state 更甚至是你要去跟後端要東西 都可以幫你整個綁起來,當然囉,最後你在頁面要import 近來render成畫面的 也會是container 不會是component
    先放張圖看看樣子 我們會再開一篇仔細說怎麼串的
    https://ithelp.ithome.com.tw/upload/images/20171222/20107767OjYnmaxj5y.png

  • 再來是一些比較像資源的東西,像是
    fonts -> 首頁要用到的資源,但是font-awesome 我有把它換成react的了,沒啥坑,裝一裝就可以用,自己google

images -> 放圖片,一個小地方要注意,如果你是在 render return裡面的話,
記得要 <img src={require('相對路徑')} />
重點來了 以我的經驗,寫專案沒有這麼完美,你可能會用到一些例外,例如這一部分
有些圖片,他偏偏就是在一些設定裡面要先給他,並不是寫在 render return
https://ithelp.ithome.com.tw/upload/images/20171222/20107767ojHGymu7Yp.png

這時候我是這樣解決的

  1. 請按照你的相對路徑 先在這個component or container 把他require進來
require('../../images/General/left_arrow.png')
require('../../images/General/right_arrow.png')
  1. 然後,就是我們剛剛拍照的樣子,webpack會把它讀取到主目錄底下
		const options = {
		    items: 3,
		    loop: true,
		    margin: 20,
		    nav: true,
		    dots: true,
		    smartSpeed: 800,
		    autoHeight: true,
		    navText: [
		    	"<div class='owl-direction'><img src='./left_arrow.png' /></FontAwesomeIcon></div>",
		    	"<div class='owl-direction'><img src='./right_arrow.png' /></FontAwesomeIcon></div>",
		    ],
		    responsive:{
		    	0: {
		    		items:1
		    	},
		    	600:{
		    		items:2
		    	},
		    	1000:{
		    		items:3
		    	}
		    }
		};

這邊我載入的圖片,是用來給 react-owl-carousel2 作為左右的箭頭的

  • languageConfig 放你多國語言的東西 這個我們昨天有說過了,就不多說
  • library 放首頁模板一開始有的.js檔案,其實有的可以刪了,但是我還是保留,以免後續錯誤,你才有辦法做追蹤
  • redux OK 這可以好好介紹一下,他的架構是這樣的

/redux/actions 放你的方法 看你是要createAction fetch 還是 dispatch 給 reducer 讓他去改狀態,都會寫在這裡

/redux/constants 主要我放model.js 還有 actionTypes.js 你把這裡想成 龜襪你的state tree 要長什麼樣子 還有什麼方法可以改變 state tree

/redux/reducers 簡而言之 剛剛我們說的action那邊會發一個dispatch出來 然後對應到了 reducer這邊後 他就會去對state tree 裡面做修改等的動作,我是有看到有人會再reducer裡面坐除了改state的事情,但是我覺得那樣會很亂,因為每種事情每個地方都有做的話,你以後Debug會滿辛苦的

/redux/stores 最後是store,這裏也沒什麼好說的,不過就是你如果有設定非同步的動作的話,這裡就要做設定
這是我configureStore.jsx的內容

Immutable 一個不會互相污染的東西
reduxThunk 非同步
rootReducer 我把我所有的reducer包在一包,一起送過來
其他自己 google or copy paste

import {createStore, applyMiddleware} from 'redux';
import { createLogger}  from 'redux-logger';
import Immutable from 'immutable';
import reduxThunk from 'redux-thunk';
import rootReducer from '../reducers';

const initialState = Immutable.Map();

export default createStore(
	rootReducer,
	initialState,
	applyMiddleware(reduxThunk, createLogger({stateTransformer: state => state.toJS() }))
  • routeConfig 我整個專案有關Route的設定我獨立拉出來 當然其實他就是一個component 但是我覺得放在component是不好的 因為它有它的獨特性 不應該把它放在大分類當中
    https://ithelp.ithome.com.tw/upload/images/20171222/20107767iLtIm5FFID.png
  • styleConfig 放你的樣式表 這個沒啥好說
  • themeConfig 這是我下載範例有的,可能之後會把它當成彩球,如果有聖誕節就可以來個聖誕節版本,啊其實你就把它當成css檔案的意思就好,只是它獨立拉出來當一個類似configuration file~ 長這樣
    https://ithelp.ithome.com.tw/upload/images/20171222/20107767WFqhxL1yzx.png

基本上專案架構就是這樣,我們來看看進入點吧
你如果有去下載一些 HTML5 的範本下來 他的 index.html 應該都會有滿多 css & script 載入 像是jquery bootstrap~
但是,那個最後你要 npm run build 就會一起死給你看
所以記得喔 該搬的要搬一搬 該用npm裝得要裝一裝 大部分會有的問題 就是我上一篇提到的 jquery loading
或是 image 的使用方式,其他應該都是一般 Google 就會有了
這就是我改完之後的 index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, height=device-height, minimum-scale=1.0, initial-scale=1.0, user-scalable=0">
  <meta name="description" content="SuccMail">
  <title>Simple is Best | SuccMail</title>

  <!-- Facebook and Twitter integration -->
  <meta property="og:title" content=""/>
  <meta property="og:image" content=""/>
  <meta property="og:url" content=""/>
  <meta property="og:site_name" content=""/>
  <meta property="og:description" content=""/>
  <meta name="twitter:title" content="" />
  <meta name="twitter:image" content="" />
  <meta name="twitter:url" content="" />
  <meta name="twitter:card" content="" />
</head>
<body>
  <div id="app"></div>
  <!--  Roboto font -->
  <script>
    var WebFontConfig = {
      google: { families: [ 'Roboto:400,300,500:latin' ] }
    };
    (function() {
      var wf = document.createElement('script');
      wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
      wf.type = 'text/javascript';
      wf.async = 'true';
      var s = document.getElementsByTagName('script')[0];
      s.parentNode.insertBefore(wf, s);
    })();
  </script>

  <!-- Delay Loading -->

</body>
</html>

最後附上 package.json 應該就可以正式的完成到可以動的專案了

{
    "name": "succmail",
    "version": "0.0.1",
    "description": "YungYuLin succmail",
    "engines": {
        "npm": ">=3"
    },
    "scripts": {
        "start": "npm-run-all --parallel test:watch open:src lint:watch",
        "open:src": "babel-node tools/srcServer.js",
        "open:dist": "babel-node tools/distServer.js",
        "lint": "esw webpack.config.* src tools --color",
        "lint:watch": "npm run lint -- --watch",
        "clean-dist": "npm run remove-dist && mkdir dist",
        "remove-dist": "rimraf ./dist",
        "prebuild": "npm run clean-dist && npm run lint && npm run test",
        "build": "babel-node tools/build.js && npm run open:dist",
        "test": "mocha tools/testSetup.js \"src/**/*.spec.js\" --reporter progress",
        "test:cover": "babel-node node_modules/isparta/bin/isparta cover --root src --report html node_modules/mocha/bin/_mocha -- --require ./tools/testSetup.js \"src/**/*.spec.js\" --reporter progress",
        "test:cover:travis": "babel-node node_modules/isparta/bin/isparta cover --root src --report lcovonly _mocha -- --require ./tools/testSetup.js \"src/**/*.spec.js\" && cat ./coverage/lcov.info | node_modules/coveralls/bin/coveralls.js",
        "test:watch": "npm run test -- --watch",
        "open:cover": "npm run test:cover && open coverage/index.html"
    },
    "author": "Yung-Yu-Lin",
    "license": "SuccMail",
    "dependencies": {
        "@fortawesome/fontawesome": "1.0.1",
        "@fortawesome/fontawesome-free-brands": "5.0.1",
        "@fortawesome/fontawesome-free-solid": "5.0.1",
        "@fortawesome/react-fontawesome": "0.0.16",
        "bundle-loader": "0.5.5",
        "expose-loader": "0.7.4",
        "flexboxgrid": "6.3.1",
        "font-awesome": "4.7.0",
        "history": "4.5.1",
        "i18next": "10.2.1",
        "i18next-browser-languagedetector": "2.1.0",
        "i18next-xhr-backend": "1.5.0",
        "immutable": "3.8.2",
        "jquery": "2.1.4",
        "material-ui": "0.17.0",
        "react": "15.4.2",
        "react-dom": "15.4.2",
        "react-i18next": "7.1.1",
        "react-owl-carousel2": "0.2.1",
        "react-redux": "5.0.6",
        "react-router": "3.0.2",
        "react-tap-event-plugin": "2.0.1",
        "recharts": "0.20.8",
        "redux": "3.7.2",
        "redux-actions": "2.2.1",
        "redux-immutable": "4.0.0",
        "redux-thunk": "2.2.0",
        "whatwg-fetch": "2.0.3"
    },
    "devDependencies": {
        "autoprefixer": "6.7.3",
        "babel-cli": "6.23.0",
        "babel-core": "6.23.1",
        "babel-eslint": "8.0.3",
        "babel-loader": "6.3.2",
        "babel-plugin-react-display-name": "2.0.0",
        "babel-plugin-transform-react-constant-elements": "6.23.0",
        "babel-plugin-transform-react-remove-prop-types": "0.3.2",
        "babel-preset-es2015": "6.22.0",
        "babel-preset-react": "6.23.0",
        "babel-preset-react-hmre": "1.1.1",
        "babel-preset-stage-1": "6.22.0",
        "babel-register": "6.23.0",
        "browser-sync": "2.18.8",
        "chai": "3.5.0",
        "chalk": "1.1.3",
        "connect-history-api-fallback": "1.3.0",
        "coveralls": "2.11.16",
        "cross-env": "3.1.4",
        "css-loader": "0.26.1",
        "enzyme": "2.7.1",
        "eslint": "3.15.0",
        "eslint-config-airbnb": "16.1.0",
        "eslint-loader": "1.9.0",
        "eslint-plugin-import": "2.2.0",
        "eslint-plugin-jsx-a11y": "4.0.0",
        "eslint-plugin-react": "6.10.0",
        "eslint-watch": "3.0.0",
        "extract-text-webpack-plugin": "1.0.1",
        "file-loader": "0.10.0",
        "html-webpack-plugin": "2.22.0",
        "isparta": "4.0.0",
        "json-loader": "0.5.7",
        "mocha": "3.2.0",
        "node-sass": "4.5.0",
        "npm-run-all": "4.0.1",
        "open": "0.0.5",
        "postcss-loader": "1.3.1",
        "prompt": "1.0.0",
        "react-addons-test-utils": "15.4.2",
        "redux-immutable-state-invariant": "1.2.4",
        "redux-logger": "3.0.6",
        "replace": "0.3.0",
        "rimraf": "2.5.4",
        "sass-loader": "6.0.1",
        "script-loader": "0.7.2",
        "sinon": "1.17.7",
        "sinon-chai": "2.8.0",
        "style-loader": "0.13.1",
        "url-loader": "0.5.7",
        "webpack": "1.13.1",
        "webpack-dev-middleware": "1.6.1",
        "webpack-hot-middleware": "2.12.2",
        "webpack-md5-hash": "0.0.5"
    },
    "keywords": [
        "SuccMail"
    ]
}

對了,突然想起,我曾經在安裝某個套件的時候 webpack 一直該該叫 最後我就把版本指定在 1.13.1
以前在寫Angular2 也是這樣~ 那今天就先到這裡囉 希望你也可以省時省力的把外面的範例
改成你想要的樣子 節省你的時間 還有 公司的成本


上一篇
【Day 3】How to Create Reactjs ?
下一篇
【Day 5】HomePage LeftDrawer and Header
系列文
React.js & Laravel 30天訓練30

尚未有邦友留言

立即登入留言