今天終於要進入React實戰階段,學習語言除了一開始練習建立Hello World,通常完整功能就是實作一套CRUD(Create、Read、Update、Delete),而todo list是最簡易的一個demo練習。是,就是走老套路線。
首先,使用CLI npm指令,先在專案folder根目錄下建立package.json:
npm init -y
再來安裝,專案會用到的相關套件:
// --save 安裝會用到的套件
// --save-dev 安裝開發會用到的套件
// webpack
npm install webpack --save-dev
// webpack hot reload 相關
npm install express webpack-dev-server webpack-dev-middleware webpack-hot-middleware --save-dev
// react 相關
npm install react react-dom --save
// babel 相關
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
建立webpack config檔案:
touch webpack.config.js
設定config內容,使用babel-loader處理js檔案,並設置plugins:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.[hash].js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
}
};
建立server.js來啟用hot reload開發環境,重點在entry必須加上webpack-hot-middleware設定,與output.publicPath指定localhost:
const path = require('path');
const webpack = require('webpack');
const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
// change webconfig for hot reload
const config = require('./webpack.config');
const webpackConfig = Object.create(config);
webpackConfig.entry = [
'webpack-hot-middleware/client?reload=true',
'./src/index.js'
];
webpackConfig.output = {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: 'http://localhost:8080/'
};
// express
const app = express();
const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath,
noInfo: true,
stats: {
colors: true
}
}));
app.use(webpackHotMiddleware(compiler));
app.get('*', function(req, res) {
// use index.html
res.sendFile(__dirname + '/index.html');
});
// listen port
app.listen(8080, function(error) {
if (error) {
console.error(error);
} else {
console.info('==> ? Listening on port %s. Open up http://localhost:%s/ in your browser.', 8080, 8080);
}
});
在server.js建立時,我們會指定render一個index.html,裡面需要有一個div,讓我們產生element可以append,然後還需要把bundle後的js放入:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>ReactTodos</title>
</head>
<body>
<div id="main"></div>
<script src="bundle.js"></script>
</body>
</html>
之後要啟用開發環境時,只需要執行:
node server.js
或是在package.json的script加上快捷指令:
"scripts": {
"dev": "node server.js"
}
然後,CLI執行:
npm run dev
建立網站entry檔案 index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
ReactDOM.render(
<App />,
document.getElementById('main')
);
按照我們最後想呈現的結果,來切割元件:
Layout架構 (root component)
├── React Todo list標題 (h1)
├── Add todo表單 (TodoAdd component)
└── Todo list元件 (TodoList component)
├── Table 標題 (thead)
└── Table 內容 (tbody)
└── Todo item元件 (TodoItem component)
從上面架構來看,我們會有app.js、TodoAdd.js、TodoList.js、TodoItem.js四個檔案,除了app.js是根元件,因為另外三個都是屬於components,可以把他們收在一個components的資料夾,以便之後檔案越來越多方便管理,如果component又可以用不同單元來區分,可以再細分成每個單元的資料夾,或是用功能區分,把同功能的js檔放一起。但這邊components還很單純,所以我們先放一個components的資料夾就可以了。
import React, { Component } from 'react';
import TodoList from './components/TodoList';
import TodoAdd from './components/TodoAdd';
class App extends Component {
render() {
return (
<div>
<h1>React Todo List</h1>
<TodoAdd />
<TodoList />
</div>
);
}
}
export default App;
import React, { Component } from 'react';
class TodoAdd extends Component {
render() {
return (
<div>
<input type="text" />
<button>Create</button>
</div>
);
}
}
export default TodoAdd;
import React, { Component } from 'react';
import TodoItem from './TodoItem';
class TodoList extends Component {
render() {
return (
<table>
<thead>
<tr>
<th>Todo</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<TodoItem />
</tbody>
</table>
);
}
}
export default TodoList;
import React, { Component } from 'react';
class TodoItem extends Component {
render() {
return (
<tr>
<td>Finish today</td>
<td>
<button>Edit</button>
<button>Delete</button>
</td>
</tr>
);
}
}
export default TodoItem;
設定完上面的檔案後,執行:
npm run dev
就可以在http://localhost:8080/看到目前的網站了,不過~我們現在還沒有加上state和props,還有點難感受到整個完整的資料流,但已經可以稍微看到拆分元件的好處,簡化了程式碼,依照功能把不同的component拆開,並且用JSX的架構很直覺可以知道這個component會呈現的樣子。
通常會看Layout來切割元件,從視覺去思考,然後也會把許多地方共用到的component切出來,可以參考官網這篇切分元件的方式,或是分久了就會有fu,比較知道怎麼拆分。
今天的檔案已經放在Git上,之後還會陸續commit,所以我把目前的階段標成v1.0,第一次使用git tag來release,算是寫文章的學習,覺得讚!