在過去的一年中兄淫,Vue的火熱讓人印象深刻屯远,但是React在github上王者地位依然鞏固,在本文發(fā)布前擁有5.7W個??捕虽,在當(dāng)下依然是最熱門的Javascript框架。本文將從最基礎(chǔ)的點(diǎn)講起并且盡量用簡短的篇幅坡脐,一步步完成一個簡單的TodoList :D
準(zhǔn)備工作
首先新建一個項(xiàng)目泄私,項(xiàng)目結(jié)構(gòu)如下:
.
├── dist
├── index.html //主頁面
├── package.json
├── src
│ ├── components
│ ├── vendor
│ ├── styles
│ └── entry.js //源js文件
└── webpack.config.js
** index.html ** 代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TodoList</title>
</head>
<body>
<div id="container">
</div>
<script src="./dist/bundle.js"></script>
</body>
</html>
** package.json ** 代碼如下,使用 * npm install * 安裝好依賴包:
{
"name": "react-todos",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"scripts": {
"dev": "webpack && node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1",
"sass": "^0.5.0",
},
"devDependencies": {
"babel-core": "^5.5.8",
"babel-loader": "^5.1.4",
"css-loader": "^0.14.5",
"express": "^4.14.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.4",
"jsx-loader": "^0.13.2",
"node-libs-browser": "^0.5.2",
"node-sass": "^3.2.0",
"react-redux": "^5.0.1",
"sass-loader": "^1.0.4",
"style-loader": "^0.12.3",
"url-loader": "^0.5.6",
"webpack": "^1.9.11"
}
}
webpack配置
webpack是當(dāng)下流行的打包工具备闲,使用webpack可以幫助我們模塊化代碼晌端、解析依賴、壓縮代碼等等恬砂,這里我們使用webpack將JSX語法轉(zhuǎn)換成純Javascript代碼咧纠,如果對webpack不太熟悉的可以先行了解下用法。其配置代碼如下:
const path = require('path');
module.exports = {
entry: './src/entry.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.js|jsx$/,
loaders: ['babel']
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
]
}
}
JSX語法
JSX語法泻骤,像是在Javascript代碼里直接寫XML的語法漆羔,實(shí)質(zhì)上這只是一個語法糖,每一個XML標(biāo)簽都會被JSX轉(zhuǎn)換工具轉(zhuǎn)換成純Javascript代碼狱掂,React 官方推薦使用JSX演痒, 當(dāng)然你想直接使用純Javascript代碼寫也是可以的,只是使用JSX趋惨,組件的結(jié)構(gòu)和組件之間的關(guān)系看上去更加清晰鸟顺。使用JSX編寫的代碼長這樣:
React.render(
<div>
<div>
<div>content</div>
</div>
</div>,
document.getElementById('example')
);
搭建基本結(jié)構(gòu)
做好了上述的準(zhǔn)備工作和知識了解后,就可以開始編寫代碼了器虾。
TodoList有用戶提交的表單和列表讯嫂,先把基本的骨架寫好,之后在逐個完善兆沙,在 ** entry.js ** 寫入以下代碼:
import React, { Component } from 'react'
import { render } from 'react-dom'
// 父組件
class ListBox extends Component {
render() {
return(
<div>
<h1>React-todoList</h1>
<ListForm />
<List />
</div>
)
}
}
// 表單組件
class ListForm extends Component {
render() {
return(
<h2>This is ListForm</h2>
)
}
}
// 列表組件
class List extends Component {
render() {
return(
<h2>This is List</h2>
)
}
}
render(
<ListBox />,document.getElementById('container')
)
以上的代碼就是寫好了ListBox父組件欧芽,和兩個子組件,最后調(diào)用render函數(shù)將它們都渲染到頁面上挤悉。
執(zhí)行webpack打包后渐裸,打開 ** index.html ** 在瀏覽器可以看到以下效果巫湘。
列表循環(huán)渲染
列表里面有多條todo,而且是動態(tài)渲染的昏鹃,首先我們在父組件的構(gòu)造函數(shù)中模擬一個假數(shù)據(jù)data來集中管理尚氛,然后用data屬性傳遞給子組件:
class ListBox extends Component {
constructor(props) {
super(props)
this.state = {
data: [
{author: "John", text: "This is first todo"},
{author: "Allen", text: "This is second todo"}
]
}
}
render() {
return(
<div>
<h1>React-todoList</h1>
<ListForm />
<List data={this.state.data}/>
</div>
)
}
}
在子組件中使用 ** this.props.data ** 接收到父組件數(shù)據(jù),然后循環(huán)遍歷出來:
class List extends Component {
render() {
let todoNodes = this.props.data.map(function(item, index){
return(
<div key={index}>
<h2>{ item.author }</h2>
<p>{ item.text }</p>
</div>
)
})
return(
<div>
{todoNodes}
</div>
)
}
}
PS:大家可能會注意到 <div key={index}>
洞渤,是因?yàn)樵赗eact中數(shù)組遍歷出來的節(jié)點(diǎn)需要定義一個唯一的 key 屬性阅嘶,這里我用的是index。
webpack打包好后载迄,可以在頁面上看到data里面的數(shù)據(jù)都已經(jīng)被渲染出來了:
表單提交
在表單中我們需要兩個輸入框和一個提交按鈕讯柔,還需要綁定提交事件,將輸入框的內(nèi)容提交給父組件:
class ListForm extends Component {
handleSubmit(e){
e.preventDefault()
let author = this.refs.author.value.trim()
let text = this.refs.text.value.trim()
if(!author && !text){
alert('please confirm input box non-blank')
return
}
//pass value to ListBox
this.props.onTodoSubmit({
author: author,
text: text
})
//clear input
this.refs.author.value = ''
this.refs.text.value = ''
}
render() {
return (
<form onSubmit={this.onTodoSubmit.bind(this)}>
<div>
<input type="text" placeholder="Name" ref="author" required/>
</div>
<div>
<input type="text" placeholder="What to do..." ref="text" required/>
</div>
<input type="submit" value="Post" className="submit-btn"/>
</form>
)
}
}
在html中寫好了一個表格护昧,綁定了一個提交事件 handleSubmit魂迄,在兩個輸入框中分別定義了 ref 屬性方便操作dom。
在提交事件中首先是阻止了默認(rèn)事件惋耙,通過 this.refs 操作dom節(jié)點(diǎn)拿到輸入框內(nèi)容捣炬,再調(diào)用父組件的 onTodoSubmit 函數(shù)將數(shù)據(jù)傳遞過去。
數(shù)據(jù)處理
現(xiàn)在要做的就是在ListBox傳遞 onTodoSubmit 屬性绽榛,并且寫好數(shù)據(jù)處理的函數(shù)就ok了:
class ListBox extends Component {
constructor(props) {
super(props)
this.state = {
data: [
{author: "John", text: "This is first todo"},
{author: "Allen", text: "This is second todo"}
]
}
}
handleTodoSubmit(todo) {
let data = Object.assign([], this.state.data)
data.push(todo)
this.setState({ data: data })
}
render() {
return(
<div>
<h1>React-todoList</h1>
<ListForm onTodoSubmit={this.handleTodoSubmit.bind(this)}/>
<List data={this.state.data}/>
</div>
)
}
}
至此一個React版的TodoList就完成了湿酸,在填寫好表單后點(diǎn)擊提交,頁面就會實(shí)時更新了灭美,其實(shí)還可以再修改下樣式和豐富一下功能推溃,比如:本地存儲、刪除todo等等届腐。對于React我也是處在摸索階段铁坎,如果文中出現(xiàn)錯誤的地方,希望大家提出來梯捕,我會馬上修改厢呵。
源碼放在了Github,如果這篇文章對您有幫助的話傀顾,可以點(diǎn)個??支持一下謝謝哈襟铭。