React开发
一. Node.js开发环境的搭建及配置
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
-
下载安装和配置
-
下载安装
-
安装成功后,打开CMD窗口,键入
node -v
-
如果提示Node命令不存在,请手动修改环境变量,将nodejs安装目录添加至path目录
-
包管理工具
常用的有3种- npm Node自带,速度较慢
- yarn 推荐使用,速度快。
- cnpm 淘宝弄得
-
配置
-
设置代理(NPM默认代理很卡,需设置为淘宝镜像)
npm config set registry https://registry.npm.taobao.org
-
安装yarn模块(强烈推荐),-g 表示全局模块
npm install yarn -g
-
-
常用的命令
-
安装模块
npm install <模块名> <-g> <--save或者--save-dev>
yarn add <模块名> <--save或者--save-dev> -
卸载模块
npm uninstall <模块名> <-g>
yarn remove <模块名>
-
-
-
开始使用Node
-
常见第一个Node项目
在D盘创建一个文件夹webapp,通过命令行创建webapp项目
D:\webapp>npm init -y
项目创建成功后,目录中多出了一个package.json文件
-
配置文件package.json
{ "name": "webapp", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
-
name:表示项目名称
-
version:版本号
-
description:描述
-
main:加载时的入口文件,当你把项目分享给别人引用时,就是别人导入的模块。
-
scripts:脚本。
命令行键入 npm test 等同于键入 echo "Error: no test specified" && exit 1
-
dependencies:依赖的模块
-
devDependencies:开发环境依赖的模块
-
license:开源协议
更多:http://blog.csdn.net/woxueliuyun/article/details/39294375
-
-
二、React开发
React是用于构建用户界面的 JavaScript 库。
官网:https://doc.react-china.org/
-
构建第一个React项目
-
添加全局模块create-react-app(官方项目模板)
npm install -g create-react-app
-
创建React项目,名为webapp
D:>create-react-app webapp --scripts-version=react-scripts-ts
-
运行
D:\webapp>yarn start
运行成功后,浏览器会自动打开该项目。
-
-
简单分析官方的项目模板里的内容
-
目录结构
- node_modules目录:存放的是项目依赖的模块(包括dependencies和devDependencies)
- @type目录:typescript类型文件(有些模块源码不是用typescript写的,因此需要额外的添加类型文件)
- script目录:带有script字眼的目录,通常是封装好的命令脚本。
- 其它:引入的模块
- public目录:静态文件或者图片。
- html文件,React会通过Js代码将项目添加到id为root的div下
- 可以新增一个css文件,进行全局样式的配置
- src目录:我们的项目
- 项目入口文件是index.tsx
- registerServiceWorker.ts是端口服务配置文件(涉及到NodeJs的API)
- package.json,NodeJs依赖关系配置文件
- tsconfig.json,typescript配置文件
- tslint.json,代码规范配置文件(暂时不敢用,要求很严格)
- node_modules目录:存放的是项目依赖的模块(包括dependencies和devDependencies)
-
package.json文件分析
{ "name": "webapp", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.2.0", "react-dom": "^16.2.0", "react-scripts-ts": "2.13.0" }, "scripts": { "start": "react-scripts-ts start", "build": "react-scripts-ts build", "test": "react-scripts-ts test --env=jsdom", "eject": "react-scripts-ts eject" }, "devDependencies": { "@types/jest": "^22.2.0", "@types/node": "^9.4.7", "@types/react": "^16.0.40", "@types/react-dom": "^16.0.4", "typescript": "^2.7.2" } }
- dependencies:依赖了三个模块react和react-dom是必须的核心模块,react-scripts-ts是react封装的webpack脚本模块。
- devDependencies:主要是依赖了typescript模块,因为React源码是用flow(类似TypeScript)写的,因此需要添加Type类型支持。
- scripts:常用的几个脚本。可以通过 npm start执行。
-
tsconfig.json文件分析
{ "compilerOptions": { "outDir": "build/dist", "module": "esnext", "target": "es5", "lib": ["es6", "dom"], "sourceMap": true, "allowJs": true, "jsx": "react", "moduleResolution": "node", "rootDir": "src", "forceConsistentCasingInFileNames": true, "noImplicitReturns": true, "noImplicitThis": true, "noImplicitAny": true, "strictNullChecks": true, "suppressImplicitAnyIndexErrors": true, "noUnusedLocals": true }, "exclude": [ "node_modules", "build", "scripts", "acceptance-tests", "webpack", "jest", "src/setupTests.ts" ] }
关键的几个配置介绍
- outDir编译后的文件路径。
- module模块化方式,(commonjs等)
- target编译后的js版本
- lib开发所有的Js版本
- rootDir是ts项目的路径。
- exclude和include,包含或不包含的文件夹。
其它的根据英文字面意思即可。
-
-
开始编写我们自己的代码
开发一个如下图的网页,点击添加,会将内容追加到下面:
[图片上传失败...(image-5e9ea2-1520993928646)]src目录下添加 APP.tsx ListComponent.tsx AddComponent.tsx
APP.tsx
import * as React from 'react'; import AddComponent from "./AddComponent"; import ListComponent from "./ListComponent"; export default class App extends React.Component<any, { data: string[] }> { private _styles = { container: { width: "100%", height: "100%", } }; constructor(prop:any,context){ super(prop, context); this.state = { data:[] } } render() { console.log("App render"); return ( <div style={this._styles.container}> <AddComponent add={(text) => this.setState({data:[...this.state.data,text]})}/> <ListComponent data={this.state.data}/> </div> ); } }
AddComponent.tsx
import * as React from "react"; export default class AddComponent extends React.Component<{ add(text): void; }, any> { private _height = "40px"; private _currValue = ""; private _styles= { container: { width: "300px", height: this._height, display: "flex", flexDirection: "row", margin: "100px", }, input: { height: "100%", flex: 1, }, add: { height: "100%", padding: "0 10px", margin: "5px 10px" } }; render() { console.log("AddComponent render"); return ( <div style={this._styles.container}> <input style={this._styles.input} type="text" placeholder="请输入要添加的内容" onChange={(event) => this._currValue = event.target.value}/> <input style={this._styles.add} type="button" value="添加" onClick={() => { this.props.add(this._currValue); }}/> </div> ); } }
ListComponent.tsx
import * as React from "react"; export default class ListComponent extends React.Component<{ data: string[] }, any> { private _styles = { container: { width: "100%", flex: 1, }, }; render() { console.log("ListComponent render"); return ( <ul style={this._styles.container}> { this.props.data.map((value, index, array) => { return ( <li>{"第" + index + "条记录," + value}</li> ); }) } </ul> ); } }
- React实现了 JavaScript 中写 HTML , HTML 中写 JavaScript
- JavaScript 中写 HTML ,是通过括号包裹的,可以写成如下:
let element = (<div><div>)
- HTML 中写 JavaScript ,是通过大括号包裹的,可以写成如下
let element = (<div>{"你好"+"!"}<div>)
- React组件必须继承React.Component,HTML布局通过render方法返回。
- React动态的更新组件式通过setState方法执行的。
- React可以通过外部传入属性,如:ListComponent组件中的data参数,获取方式是:this.props.data。
- 样式文件直接使用JSON来写即可,通过style引入。
React是单向数据流单页面组件,每次刷新都会调用render方法,手动刷新是通过调用setState方法。
烦恼:- 由于刷新组件只能通过setState进行,意味着只能在组件内部进行更新页面。
- 由于是单向数据流,因此无法修改父组件传过来的属性,但是有时候就是要修改。
这时候数据绑定模块就出现了,主要有两种mobx和redux,redux虽然是主流,但是使用起来非常繁琐,Mobx是后起之秀,结合了redux的理念,操作简单,容易上手,网上也有相关的对比。
- React实现了 JavaScript 中写 HTML , HTML 中写 JavaScript
-
Mobx的使用
-
项目引入Mobx模块
修改package.json文件,在dependencies节点添加"mobx": "^3.6.1", "mobx-react": "^4.4.2",
执行命令行安装
yarn install
2. 修改App.tsx和ListComponent.tsx文件import * as React from 'react'; import AddComponent from "./AddComponent"; import ListComponent, {appState} from "./ListComponent"; export default class App extends React.Component<any, { data: string[] }> { private _styles = { container: { width: "100%", height: "100%", } }; constructor(prop:any,context){ super(prop, context); this.state = { data:[] } } render() { console.log("App render"); return ( <div style={this._styles.container}> <AddComponent add={(text) => appState.add(text)}/> <ListComponent/> </div> ); } }
import * as React from "react"; import {observer} from "mobx-react"; import {observable} from "mobx"; class AppState { @observable data: string[] = []; add(text:string){ this.data = [...this.data, text]; } } export const appState = new AppState(); @observer export default class ListComponent extends React.Component<any, any> { private _styles = { container: { width: "100%", flex: 1, }, }; render() { console.log("ListComponent render"); return ( <ul style={this._styles.container}> { appState.data.map((value, index, array) => { return ( <li>{"第" + index + "条记录," + value}</li> ); }) } </ul> ); } }
yarn start 运行即可
-
原理简单分析
- observable 被观察者,mobx实时监测被观察者的变化,如果发生变化,就会通知observer更新。
- observer 观察者,收到observable的更新通知后,observer会检查这个observable自己有没有在使用,如果在使用,就会更新(调用render方法)
-
-
单页面跳转必备-路由器 router
官网:https://react-guide.github.io/react-router-cn/-
项目引入react-router模块
修改package.json, 在dependencieshe和节点添加"dependencies": { "history": "^4.6.2", "react-router-dom": "^4.2.2", }, "devDependencies": { "@types/history": "^4.6.2", "@types/react-router-dom": "^4.2.2", }
执行命令行安装
yarn install
-
开始编写路由器
修改APP.tsximport React from "react"; import {Route, Router} from "react-router"; import {createBrowserHistory} from "history"; export const browserHistory = createBrowserHistory(); export default class App extends React.Component{ render(){ return( <div style={{width:"100%",height:"100%",display:"flex",flexDirection:"column"}}> <ul> { ["nav1","nav2"].map((value, index, array)=>{ return( <li onClick={()=>{ if(index ===0){ browserHistory.push("/first") }else if(index ===1){ browserHistory.push("/second") } }}>{value}</li> ); }) } <Router history={browserHistory}> <div> <Route exact path="/" component={Home}/> <Route path="/first" component={First}/> <Route path="/second" component={Second}/> </div> </Router> </ul> </div> ); } } class Home extends React.Component{ render(){ return( <div> Home界面 </div> ); } } class First extends React.Component{ render(){ return( <div> First界面 </div> ); } } class Second extends React.Component{ render(){ return( <div> Second界面 </div> ); } }
yarn start 运行即可
-
原理简单分析
- 待定,未知。
-
三、Webpack打包机
官网:http://www.css88.com/doc/webpack/
他可以轻松的处理 JavaScript 依赖关系和加载顺序,并按规则打包或压缩成指定格式。
-
原理介绍
[图片上传失败...(image-91324f-1520993928646)]
有了打包机:
- 项目可以使用更高级的JS语法(ES6以上)。
- 项目可以使用更牛逼的TS语法
- 项目可以轻松的压缩成单js css文件
- 项目可以编译成指定ES版本的JS语法(目前浏览器完美支持es5)
- 项目可以把HTML写进JS文件,在根据loader转换成HTML(React)
- 很多很多。。。。只有你有对应loader。
-
webpack语法的简单介绍
可以在根目录新增一个webpack.config.js配置文件,通过webpack --config webpack.config.js 运行。const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ title: 'Output Management' }) ], };
- entry:入口文件。
- output:输出路径
- rules:规则配置,上面例子中配置了 当发现css文件时的处理方式。
- plugins:插件,使用别人封装好的插件处理,比如发现html文件时使用的HtmlWebpackPlugin
-
第一个loader(less)
该例子背景是重新创建一个react-appD:>create-react-app webapp --scripts-version=react-scripts-ts
-
修改package.json,增加两个dev依赖
"less": "^3.0.1",
"less-loader": "^4.0.6",执行 yarn install 安装
-
打开路径node_modules/react-scripts-ts 这是react封装好的webpack
-
打开scripts/build看看build过程中,是引用了那个webpack.config配置。
const webpack = require('webpack'); const config = require('../config/webpack.config.prod'); function build(previousFileSizes) { console.log('Creating an optimized production build...'); let compiler = webpack(config); ...省略... }
由代码可知,build使用的config路径是"../config/webpack.config.prod"
-
打开这个webpack.config.prod文件,找到rules(打包规则)配置中关于css的解析,因为less本身属于css的范畴。
{ test: /\.css$/, loader: ExtractTextPlugin.extract( Object.assign( { fallback: { loader: require.resolve('style-loader'), options: { hmr: false, }, }, use: [ { loader: require.resolve('css-loader'), }, { loader: require.resolve('postcss-loader'), }, ], }, ) ), },
test:目前只支持css文件,所以需要增加对less文件的支持,
test: /.(css|less)$/,
loader:目前只用了postcss-loader-->css-loader-->style-loader 需要增加ls-loader支持
loader: require.resolve('less-loader')
修改后的配置
{ test: /\.(css|less)$/, loader: ExtractTextPlugin.extract( Object.assign( { fallback: { loader: require.resolve('style-loader'), options: { hmr: false, }, }, use: [ { loader: require.resolve('css-loader'), }, { loader: require.resolve('postcss-loader'), }, { loader: require.resolve('less-loader'), } ], }, ) ), },
同理,我们修改start脚本的配置(因为start脚本用的是另一个config)。
测试是否配置成功
- 将原来的 App.css 修改为 App.less
- 修改App.tsx文件中的 import './App.css'; 修改为 import './App.less';
运行即可。
-
四、TypeScript简单介绍
官网:https://www.tslang.cn/
TypeScript是JavaScript的超集,它的存在并不是为了取代JavaScript,而是辅助JavaScript实现类型检查,直到ES支持强类型,TypeScript就是可以光荣退休了。
未来:TypeScript不存在淘汰的问题,因为它采用的是JavaScript语法,他所做的仅仅是增加了强类型。
比如:
let a:string = "test";
编译成ES6
let a = "test";
编译成ES5
var a = "test";
所有的强类型在编译成JavaScript后都会消失。
TypeScript类型的定义
基础数据类型
- string 字符串
- number 数字
- object 对象
- undefined 未定义
- {} 对象 可以指定成员
- any 任意对象,懒人专用,定义后,typescript下岗了。
组合使用
- {[key:string]:number} key为string value为number的对象
第一种:
interface IPerson{
name:string;
}
interface IStudent extends IPerson{
score?:string;
}
let student:Iprop;
第二种
type IStudent = {
name:string;
score?:string;
}
let student:Iprop;
第三种
let student:{name:string;score?:string;};
? 表示这个属性可有可无 student.score===undefined || string
四、辅助工具
-
cmder(推荐)
一款支持复制粘贴,支持linux命令的windows命令行工具,选用。
相关文章 http://blog.csdn.net/wnma3mz/article/details/78268463 -
WebStorm
- WebStorm 的破解
下载地址:https://www.jetbrains.com/webstorm/
license server http://idea.ibdyr.com - WebStorm配置
开发语言的选择 File | Settings | Languages & Frameworks | JavaScript 默认的开发语言是ES6 修改为React JSX即可。
- WebStorm 的破解
-
其它开发工具
- VSCode(免费) VS的压缩版本
- VS
- Notepad+ 或 记事本
- Xcode
五、其它
-
我的tsconfig配置文件
{ "compilerOptions": { "outDir": "build/dist", "module": "esnext", "target": "es5", "lib": ["esnext","dom"], "jsx": "react", "rootDir": "src", "forceConsistentCasingInFileNames": true, "noImplicitReturns": true, "suppressImplicitAnyIndexErrors": true, "removeComments": true, "preserveConstEnums": true, "moduleResolution": "node", "experimentalDecorators": true, "noImplicitAny": false, "allowSyntheticDefaultImports": true, "noUnusedParameters": false, "noUnusedLocals": false, "strictNullChecks": true, "noImplicitThis": true, "sourceMap": true, "allowJs": false, "allowUnreachableCode": true, "allowUnusedLabels": true, "checkJs": false, "baseUrl": "." }, "exclude": [ "node_modules", "build", "scripts", "acceptance-tests", "webpack", "jest", "src/setupTests.ts" ], "include": [ "src" ], "compileOnSave": true }
outDir:编译后 build/dist目录下会出现编译后的文件。
module:模块化规范(commonjs等),好几种。
target:编译后的es版本,通常就是es5,浏览器支持es5,es6没有普及。
lib:开发过程中使用的es版本,看心情。
jsx:react或者react-native,native是移动端混合APP开发用的。
rootDir:项目所在位置。
sourceMap:如果没有souceMap,浏览器出现的一堆压缩过后的Js文件,很难受。没法调试。
其它有道词典走一波即可。 -
React的编程思想
- 响应式
- 组件化
-
React更新组件的算法
倘若git采用的算法叫做逐行算法,那么React采用的算法是同行算法。
网友评论