create-react-app
通过创建一个已经完成基本配置的应用,让开发者快速开始React应用的开发。
安装
npm install --global create-react-app
安装后可执行create-react-app 项目名
操作。
以上操作后会在当前目录下创建一个first_react_app目录,目录中自动添加一个应用的框架,我们只需要修改文件即可。
之后输入命令:
cd first_react_app
npm start
这个命令会启动 个开发模式的服务器,同时也会让你的浏览器自动打开了 个网页,指向本机地址 http://localhost:3000
感觉
create-react-app
类似于vue
中的vue-cli
,即满足热刷新和项目架构的搭建。
JSX语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="reactContainer"></div>
</body>
<script src="react.js"></script>
<script src="react-dom.js"></script>
<script src="http://cdn.bootcss.com/babel-core/5.8.38/browser.min.js"></script>
<script type="text/babel">
var HelloComponent = React.createClass({
render:function(){
return <h1>Hello { this.props.name ? this.props.name:"world" }</h1>;
}
});
ReactDOM.render(
<HelloComponent name="nijiagugu"/>,
document.getElementById("reactContainer")
)
</script>
</html>
state
state是一个状态集合,开发者的主要工作就是定义state,并根据不同的state渲染对应的用户界面。
以下通过一个点击按钮切换input可用性的例子来解析state。
初始化state
这里我所理解的state,就是Vue中的data数据,在其他方法中访问时需要加上this.state
。
getInitialState: function(){
return {enable:true};
}
添加事件处理方法
点击切换可用性。
handleClick:function(event){
this.setState({enable:!this.state.enable})
}
挂载
ReactDOM.render(
<HelloComponent/>,
document.getElementById("reactContainer")
)
全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="reactContainer"></div>
</body>
<script src="react.js"></script>
<script src="react-dom.js"></script>
<script src="http://cdn.bootcss.com/babel-core/5.8.38/browser.min.js"></script>
<script type="text/babel">
var HelloComponent = React.createClass({
getInitialState: function(){
return {enable:true};
},
handleClick:function(event){
this.setState({enable:!this.state.enable})
},
render:function(){
// return <h1>Hello { this.props.name ? this.props.name:"world" }</h1>;
return (
<p>
<input type="text" disabled={this.state.enable}/>
<button onClick={this.handleClick}>改变可用性</button>
</p>
)
}
});
ReactDOM.render(
<HelloComponent/>,
document.getElementById("reactContainer")
)
</script>
</html>
props
实际上就是属性值,可通过在标签中通过
属性名="属性值"
设置。
生命周期
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
子属性
props属性验证
通过propsTypes进行属性验证。如我们获取的父级元素的值的属性必须要不为空,onClick必须是函数等限定。
用法
propTypes:{
title:React.PropTypes.string.isRequired,
}
PropTypes告诉React,这个title属性是必须的,而且它的值必须是字符串。
否则,会在控制台报Warning。
propTypes的更多设置
//TODO
props默认属性值
getDefaultProps
getDefaultProps:function(){
return {
title:'Hello JSPang'
}
},
render:function(){
return(
<h2>{this.props.title}</h2>
)
}
获取真实Dom节点
react是虚拟的DOM的节点,只渲染变化的部分。
ref
可简单的理解为id来获取当前节点。
var AddCount=React.createClass({
render:function(){
return(
<div>
<input type="text" ref="myTextInput"/>
<input type="button" value="Focus mouse" onClick={this.handleClick}/>
</div>
)
},
handleClick:function(){
this.refs.myTextInput.focus();
}
})
ReactDOM.render(
<AddCount/>,
document.getElementById("demo")
);
react表单
自动监控表单内容变化
通过state和onChange事件来触发数据的响应变化。
实现
var MyForm = React.createClass({
getInitialState:function(){
return{
value:"hello"
}
},
handleChange:function(event){
this.setState({value:event.target.value});
},
render:function(){
var value = this.state.value;
return (
<div>
<p>{ value }</p>
<input type="text" value={ value } onChange={ this.handleChange } />
</div>
)
}
});
ReactDOM.render(<MyForm/>,document.getElementById('demo'))
可控组件
在render
中设置input
的value
是不可以改变的。
var MyForm = React.createClass({
render:function(){
return (
<div>
<input type="text" value="hello" />
</div>
)
}
});
ReactDOM.render(<MyForm/>,document.getElementById('demo'));
必须通过state
的方式绑定初始值。
通过onChange
绑定事件。
可控组件就是value必须绑定到state上,必须监控onChange事件,实时监控。
不可控组件
不可控组件是不绑定state值,虽然可以通过onChange监听变化,但是需要获取他的DOM
generator-react-webpack
一款集成了webpack的脚手架。但是需要yeoman的支持
安装
npm install -g yo
npm install -g generator-react-webpack
创建目录
mkdir new-react-demo
cd new-react-demo
生成项目目录
yo react-webpack
起服务
npm start
用webpack配置react开发环境
- 项目初始化
npm init
- 安装webpack
npm install --save-dev webpack
- 配置webpack.config.js
创建webpack.config.js
文件
var path =require('path');
module.exports = {
//入口文件
entry:'./app/index.js',
//出口文件
output:{
filename:'index.js',
path:path.resolve(__dirname,'dist')
}
}
- 创建dist目录、app目录、app目录下的index.js文件、根目录下创建index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ReactWebpack</title>
</head>
<body>
</body>
<script src="./dist/index.js"></script>
</html>
这里引入的是出口文件
- 在packge.json中加入build命令
"scripts": {
"build": "webpack"
},
- 配置服务器
cnpm install --save-dev webpack-dev-server
在webpack.config.js中配置
devServer:{
contentBase:'./',
host:'localhost',
compress:true,
port:1717
}
- 在packeage.js添加script命令
"scripts": {
"build": "webpack",
"server": "webpack-dev-server --open"
},
- 配置自动刷新
在webpack.config.js中的output中添加一项配置
output:{
filename:'index.js',
path:path.resolve(__dirname,'dist'),
publicPath:'temp/'
},
在index.html中修改script引用路径为./temp/index.js
重启服务器即可实现自动刷新。
- Babel安装
cnpm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
- 配置module
module:{
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
loaders:"babel-loader",
query:{
presets:['es2015','react']
}
}
]
}
- 安装react
cnpm install react react-dom
- 修改app/index.js
import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render(
<div>Hello world</div>,
document.getElementById("app")
);
打包命令
npm run --dev=dist
路由
安装路由
npm install --save react-router react-router-dom
两个包都可以运行,但是React-router包括Router、Route、Switch等,但是没有提供DOM操作进行跳转的api。
React-router-dom可以通过DOM事件控制路由进行跳转。
- 通过es6的继承写法新建一个自定义组件
gugu.js
import React from "react"
export default class gugu extends React.Component{
render(){
return(
<div>A默认页面</div>
)
}
}
- 在app/index.js下引入自定义组件
import Gugu from "./gugu"
- 新建一些差不多的组件以便后面路由使用
import Gugu from "./gugu"
import Gugua from "./gugua"
import Gugub from "./gugub"
- 引入路由
在index.js中写:
import {BrowserRouter as Router,Route} from "react-router-dom"
Router相当于一个容器,Router是一个路由
修改(编写)路由:
ReactDOM.render(
<Router>
<div>
{/* exact是这里的exact是精确匹配的意思,比如我们有多层路由进行嵌套时,exact可以帮助我们精确匹配到你想跳转的路由。 */}
<Route exact path="/" component={Gugu} />
<Route path="/Gugua" component={Gugua} />
<Route path="/Gugub" component={Gugub} />
</div>
</Router>,
document.getElementById("app")
);
- 编辑导航Nav
新建一个组件nav.js
import React from "react"
import {NavLink} from "react-router-dom"
const Nav = () =>(
<div>
<div>
<NavLink exact to='/'>Gugu</NavLink> |
<NavLink to='/Gugua'>Gugua</NavLink> |
<NavLink to='/Gugub'>Gugub</NavLink>
</div>
</div>
)
export default Nav;
- 在app/index.js中挂载这个组件
import Nav from "./nav"
ReactDOM.render(
<Router>
<div>
<Nav/>
{/* exact是这里的exact是精确匹配的意思,比如我们有多层路由进行嵌套时,exact可以帮助我们精确匹配到你想跳转的路由。 */}
<Route exact path="/" component={Gugu} />
<Route path="/Gugua" component={Gugua} />
<Route path="/Gugub" component={Gugub} />
</div>
</Router>,
document.getElementById("app")
);
直接输入url是无法访问路由的
NavLink
给NavLink加样式。
- 增加一个nav.css文件
.blue{
color: red;
}
- 在nav.js中引入
import "./nav.css"
- 配置webpack
安装style-loader
cnpm install --save-dev style-loader css-loader
在webpack.config.js中添加配置
{
test:/\.css$/,
loader:['style-loader','css-loader']
}
NavLink中的active
指的链接的激活状态。
<div>
<div class="blue">
<NavLink exact to='/' activeClassName="bbb">Gugu</NavLink> |
<NavLink to='/Gugua' activeClassName="bbb">Gugua</NavLink> |
<NavLink to='/Gugub' activeClassName="bbb">Gugub</NavLink>
</div>
</div>
activeClassName
为激活状态应用的类名。
HashRouter和BrowserRouters
HashRouter会让URL中默认有一个井号(#),而BrowserRouter则不会有这个井号(#)
Link和NavLink
两者都是可以控制路由跳转的,不同点是NavLink的api更多,更加满足你的需求。
NavLink
它可以为当前选中的路由设置类名、样式以及回调函数等。
match
用于页面传参。
/second/:id
在新的路由页面中获取这个id,需要用到match。
获取的时候用this.props.match.params.id
,id是之前定义好的属性值。
多参数传递
此种方式不常用,但可以实现
/second/:id/:name
之后可通过this.props.match.params.id
,this.props.match.params.name
获取。
404设置
利用switch
。
- 在index.js中引入Switch
import {BrowserRouter as Router,Route,hashHistory,HashRouter,Switch} from "react-router-dom"
- 创建一个不存在的NavLink
<Link to='/Gusdb' activeClassName="bbb">404</Link>
- 引入404组件,并为其配置路由
import Error from "./nomatch"
ReactDOM.render(
<Router history={hashHistory}>
<div>
<Nav/>
{/* exact是这里的exact是精确匹配的意思,比如我们有多层路由进行嵌套时,exact可以帮助我们精确匹配到你想跳转的路由。 */}
<switch>
<Route exact path="/" component={Gugu} />
<Route path="/Gugua/:id" component={Gugua} />
<Route path="/Gugub" component={Gugub} />
<Route component={Error}/>
</switch>
</div>
</Router>,
document.getElementById("app")
);
switch中,404页面必须放在最下方。
Redirect跳转
在开发中有时候遇到根据业务逻辑进行跳转,需要用到Redirect,但是Redirect必须有Switch的支持
- 引入Redirect
import {BrowserRouter as Router,Route,hashHistory,HashRouter,Switch,Redirect} from "react-router-dom"
- 加入跳转链接
<Link to='/redirect' activeClassName="bbb">Redirect</Link>
- 加入<Redirect>标签
在index.js中添加标签。
<Redirect from="/redirect" to="/" />
路由的其他属性
basename
增加路由层级。
forceRefresh
强制刷新
forceRefresh={true}
加上他,路由将会失效。
路由模式
BrowserRouter
:浏览器的路由方式,也是我们一直在学习的路由方式,在开发中最常使用。
HashRouter
:在路径前加入#号成为一个哈希值。Hash模式的好处是,再也不会因为我们刷新而找不到我们的对应路径了。
MemoryRouter
:不存储history,所有路由过程保存在内存里,不能进行前进后退,因为地址栏没有发生任何变化。
NativeRouter
:经常配合ReactNative使用,多用于移动端
StaticRouter
:设置静态路由,需要和后台服务器配合设置,比如设置服务端渲染时使用。
Prompt标签
react-router提供的一个标签,提示的意思。
import React from "react"
import {Prompt} from 'react-router-dom';
export default class gugub extends React.Component{
render(){
return(
<div>
<div>bb默认页面</div>
<Prompt message="残忍离开?"/>
</div>
)
}
}