React 特色:声明式设计、虚拟DOM、JSX、组件、数据驱动。javascript
# 安装node.js 从而安装npm,它会在当前用户家目录下生成node_moudules文件夹,来对npm安装的全局第三方包进行管理 brew install node
# npm安装cnpm,由于npm默认的库下载速度太慢,因此建议使用cnpm指定淘宝库 npm install -g cnpm --registry=https://registry.npm.taobao.org npm config set registry https://registry.npm.taobao.org # 测试 cnpm install express -g
# 安装create-react-app
cnpm install create-react-app -g
# 利用create-react-app 来建立一个项目
create-react-app 项目名称 # 假设这里的项目名称是my-app
# 进入项目文件夹
cd my-app
# 生成配置文件
# cnpm run eject # 生成scripts文件夹和config文件夹,cnpm
# 启动服务
cnpm start # 它至关于执行 scrpits/starts.js,这个已经在package.json中配置好了
my-app - config # 项目默认配置文件,由npm run eject生成 - .gitignore # git配置 - node_modules # 本地第三方安装包 - package.json # npm项目配置,里面记录了项目的名字、版本、依赖包、和自定义配置 - package-lock.json - public # 公共资源 - index.html # 静态页面 - README.md - scripts # 配置pacakage.json中的"scripts"定义的命令 - build.js # build命令,可由npm build执行,生成静态文件用于迁移到生产环境 - start.js # start命令 - test.js - src - App.css # 建立项目时自动生成的css样式,没用 - App.js # react组件 - App.test.js - index.css # 入口文件的样式 - index.js # 入口文件 - log.svg - registerServiceWorker.js
项目启动时,会加载public下的index.html文件,并进而执行index.js,从而完成整个页面的渲染。css
<!--public/index.html简化以下-->
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>React App</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <div id="root"></div> </body> </html>
react简单示例只保留简化后的public/index.html和src/index.jshtml
React.Component是自定义组件的父类,必须重写render方法来完成组件的声明和返回。所谓组件,就是用js类定义的一组html标签、样式、数据、事件等的整合,该类能够用<类名 />的方式进行标签化(实例化),实例化时自动调用render方法,并最终交由React.render完成渲染。java
一张网页就能够分割成多个组件,每一个组件本身实现标签、样式、数据交互和用户交互。也就是说,网页是由多个组件堆砌而成的,每一个组件都必须继承React.Component来实现并返回本身的定制化。显然地,组件既包含一个div标签组,自己也是一个类,它具备双重角色。node
一个继承了React.Component的组件,经过render返回一个组件对象。经验上谈,一个子类的某个固定方法极有多是其父类方法(或接口)的重写(实现),而每每这个方法会在程序运行时被自动调用。所以,render方法是重写了React.Component,在程序启动时被自动执行,挂载到网页的某个节点上。react
import React, {Component, Fragment} from "react"; class Boom extends Component{ render() { return ( <Fragment> <div> <input /><button>提交</button> </div> <ul> <li>what the hell?</li> <li>你瞅啥子</li> </ul> </Fragment> ) } } export default Boom;
index.js中的ReactDOM.render函数用于将标签或者组件渲染到public下的页面中。第一个参数能够是任意的单个标签、div包裹的多个标签,以及自定义的组件Component。git
ReactDOM.render用于将组件挂载到某个标签上。好比html中某个id为root的div标签上。简单粗暴:一个包含了西瓜瓤、西瓜籽、西瓜皮的西瓜挂在了西瓜藤上。express
用于编译jsx语法。React.Component和ReactDOM.render中的标签都使用了jsx语法,因此必须使用React进行编译。JSX看起来像是急于XML的javascript的扩展。它编写简单而且执行更快,同时也是类型安全的,在编译过程当中就能发展错误。npm
经验之谈:若是一个标签的首字母时大写,那么它就遵循JSX语法,若是一个标签的首字母小写,那么它就是原始html标签(但这个标签有多是按照jsx语法编译的)。json
JSX容许在一对{}中写js代码,例如:
{ /* 遍历list生成li标签,并给每一个li标签添加删除功能 / this.state.list.map( (item, index) => { return <li key={index} onClick={(index)=>{this.handleLiDelete(index)}} > { item }</li> }
) }
组件内部能够声明参数,不管是textNode仍是其它Node,都是以 { 参数 } 的形式被组件调用。组件react虚拟DOM的具体实现方式,它来完成对页面和业务逻辑的划分。
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
render (){
const string = "hello, react!";
const style1 = {
color: "white"
};
const style2 = {
textAlign:"center",
fontStyle: "border",
backgroundColor: "green"
};
return (
<div style={style1}>
{/*这是一段注释*/}
<h2 style={style2}>{ string }</h2>
</div>
)
}
}
ReactDOM.render(<div>
<h2>hello, react!</h2>
<App />
</div>, document.getElementById('root'));
组件间能够实现嵌套。
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
render (){
return <h2>这是子组件</h2>
}
}
class App2 extends React.Component{
render (){
const style = {
backgroundColor: "blue"
};
return (
<div style={style}>
<h2>这是父组件</h2>
<App />
</div>
)
}
}
ReactDOM.render(<App2 />, document.getElementById('root'));
组件间数据经过this.props属性来进行数据传递。父组件在标签化时经过属性的方式传递数据,子组件经过this.props来获取全部的数据。
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
render (){
return <h2>App: { this.props.name }, { this.props.age }</h2>
}
}
class App2 extends React.Component{
render (){
const name = "Sun", age=5000;
return (
<div>
<h2>App2: { this.props.name }, { this.props.age }</h2>
<App name={name} age={age} />
</div>
)
}
}
ReactDOM.render(<App2 name="Li" age="20" />, document.getElementById('root'));
注意:1.props只能传递静态数据,没法与用户交互;2.{}不是Object对象,若是想写<App2 obj={name: "Li", age: 20} />,就必须提早声明。3.style样式做为数据传递是无效且荒谬的。
const obj = {name: "Li",age: 20};
<App2 obj={obj}/>
React是一个响应式框架,它将数据和dom分开,可以根据数据的变化自动更新dom。再次强调:React.Component具备双重属性:组件(dom)属性和js类属性(类:数据封装)。
state用于负责处理动态数据。数据须要在构造函数中经过this.state事先声明,并在事件中经过this.setSate完成数据更新。
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
constructor(props){
super(props);
this.state = {
nameList:["Sun", "Li", "Zhao", "Qian"]
}
}
addPerson(){
this.setState({
nameList: [...this.state.nameList, "zhou"]
})
}
render (){
return (
<div>
<button onClick={()=>this.addPerson()}>加入周先生</button>
<ul>
{this.state.nameList.map((name, index) => <li key={index+1}>{name}</li>)}
</ul>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
在react中,事件以属性的方式直接在标签中使用,其调用函数要用一层函数包裹。调用函数能够直接写在对象内部,而且要用bind进行监听和更新。
在上面的示例中,咱们经过这一行代码代替了bind的过程:
<button onClick={()=>this.addPerson()}>加入周先生</button>
鉴于js中没有局部做用域只有函数做用域,因此若是直接写onClick={this.addPerson}时,this指的就是window对象。用一层函数包裹时,this对象指的就是这个函数。
其它的作法有两种:
首先,在事件绑定时直接使用this.function:
<button onClick={this.addPerson}>加入周先生</button>
其次能够用箭头函数来声明addPerson函数,本质上和上面使用的方法同样:
addPerson = ()=>{
this.setState({
nameList: [...this.state.nameList, "zhou"]
})
};
或者能够不改addPersonn函数,而是在构造器中添加上这么一句话:
this.addPerson = this.addPerson.bind(this)
一个示例:
import React, {Component, Fragment} from "react"; class Boom extends Component{ constructor(props){ super(props); this.state = { inputValue: "", list: [] } } handleInputChange(e){ this.setState({ inputValue: e.target.value }); } handleBtnClick(){ this.setState({ list:[...this.state.list, this.state.inputValue], inputValue: "" // 在提交时自动清空输入框里的内容 }) } handleLiDelete(index){ const list = [...this.state.list]; // 只能经过setState修改数据,因此不要写成this.state.list.splice(index, 1); list.splice(index, 1); this.setState({ list: list }); } render() { return ( <Fragment> <div> <input value={ this.state.inputValue } onChange={this.handleInputChange.bind(this)} /> <button onClick={()=>this.handleBtnClick()}>提交一个句子</button> </div> <ul> { this.state.list.map( (item, index) => { return <li key={index} onClick={(index)=>{this.handleLiDelete(index)}} > { item }</li> } ) } </ul> </Fragment> ) } } export default Boom;
render自己是一个实例方法,支持js中的各类代码逻辑。能够用if-else来控制返回结果。条件渲染在用户登陆和重定向中使用的比较频繁。
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
constructor(props){
super(props);
this.state = {isLogIn: false}
}
login (){
this.setState({isLogIn: true})
};
logout(){
this.setState({isLogIn: false})
}
render (){
let button=null;
if (this.state.isLogIn){
button = <button onClick={()=>this.logout()}>注销</button>
}else {
button = <button onClick={()=>this.login()}>登陆</button>
}
return button
}
}
ReactDOM.render(<App />, document.getElementById('root'));
也能够用三元表达式简写:
render (){
return (
<div>
{this.state.isLogIn ? <button onClick={()=>this.logout()}>注销</button> : <button onClick={()=>this.login()}>登陆</button>}
</div>
)
}
注意:因为{}传递的数据能够是任意值,因此须要用div包裹。