| react-create-app 脚手架
| Router、Route
| Link、Links router的导航组件,用来切换路由
| browserHistory、hashHistory
| activeStyle、activeClassName 路由设置样式
| query、params 变量
| Redirect
react-create-app 脚手架
$ sudo npm i create-react-app -g // 全局安装,以后在安装就直接使用create-react-app命令来创建就可以
$ create-react-app my-app // 创建+创建项目目录名
$ cd my-app
$ yarn start
$ yarn start、yarn build // 启动服务、打包
$ yarn add antd // 安装Antd UI框架
在index.js中引用ant公用样式
import 'antd/dist/antd.css';
$ yarn add react-router-dom -D // react-router是安装4.0之前版本,react-router-dom是4之后版本
$ yarn add redux react-router-redux -D
$ npm run eject // 注意如果对构建工具和配置选择不满意可以使用eject运行, 这里是单项操作只能一次不能回去
一、create-react-app关闭eslint提醒
需要先npm run eject 生成本地webpack配置文件,在修改package.json中的配置
"eslintConfig": {
"extends": "react-app",
"rules": {
"no-undef": "off",
"no-restricted-globals": "off",
"no-unused-vars": "off"
}
}
二、配置反向代理
"proxy": {
"/api/*": {
"target": "http://goucai.diyicai.com",
"pathRewrite": {
"^/api/": "/"
},
"changeOrigin": true,
"secure": false
}
}
三、使用.scss文件
1、$ npm install file-loader sass-loader node-sass --save-dev // 安装包
2、node_modules/react-scripts/config/webpack.config.dev.js 和 webpack.config.prod.js文件中module中配置下面两项
{
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/, /\.scss/], // 这里加添加一个/\.scss/
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
}
},
// 解析scss文件
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
}
四、引入样式
1、<div style={{width: "1000px"}}></div>
2、import "./main.css"
<div className="main"></div>
3、import Styles from './main.css'
<div className={Styles.main}></div>
五、常见问题
1、<src>引用本地图片无效
import JzkUrl from '../../assets/img/jzk.png'
<img src={JzkUrl} />
六、build的打包的时候注意的地方
在package.json中的有一个homePage: '.',这个在打包的时候图片会成为相对路径,如果改成 homePage: '/'
七、修改webpack配置加一个全局配置
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
resolve: {
alias: {
'react-native': 'react-native-web',
'@': resolve('src')
}
}
在页面里可以直接引用@来找到src目录
import User from '@/views/User/'
PropTypes验证
React.PropTypes 提供很多验证器来验证传入数据的有效性
当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes。下面用例子来说明不同验证器的区别:
Example:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
propTypes类型: {
// 可以声明 prop 为指定的 JS 基本类型。默认
// 情况下,这些 prop 都是可传可不传的。
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 所有可以被渲染的对象: 数字,
// 字符串,DOM 元素或包含这些类型的数组。
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 指定的多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定形状参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 以后任意类型加上 `isRequired` 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,
// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
// 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
}
react-router 4.0
v3到v4版本的变化是静态路由到动态路由的变化,并且页面的嵌套路路由嵌套决定
react-router: 是浏览器和原生应用的通用部分, 核心文件
react-router-dom: 用于浏览器
react-router-native: 是用于原生(react-native)应用的
react-router-redux: React Router 和 Redux 的集成
react-router-config: 静态路由配置的小助手
一、安装
$ npm i react-router react-router-dom --save
import { BrowserRouter as Router, Route, Switch, Link, Redirect, withRouter } from 'react-router-dom';
二、使用路由
1、react-router和react-router-dom,不需要都引用,只是后者多<Link> <BrowserRouter> 这样的 DOM 类组件
2、如果搭配 redux ,你还需要使用 react-router-redux
index.js: 在入口文件加上路由配置
import React from 'react'
import { Router, Route, Link } from 'react-router'
// render中加入路由配置
React.render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.body)
二、<BrowserRouter> HTML5 history路由组件
1、basename - 为所有位置添加一个基准的url
<BrowserRouter basename="/minooo" />
<Link to="/react" /> // 最终渲染为 <a href="/minooo/react">
2、getUserConfirmation() - 导航到此页执行的函数
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation('Are you sure?', yourCallBack)} />
3、forceRefresh - bool当浏览器不支持 HTML5 的 history API 时强制刷新页面
const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory} />
4、keyLength - 路由的长度
5、children - 渲染唯一子元素
三、<HashRouter> 该技术只是用来支持旧版浏览器, Hash history 不支持 location.key 和 location.state
四、<Route> 最重要的组件,页面访问地址与Router的path进行匹配,渲染出对应的UI界面
<Route path="/" component={Main}> - 渲染的组件
<Route> 自带三个 render method 和三个 props
1、render methods 分别是:
<Route component> - 当访问地址和路由匹配时,一个组件才会被渲染,此时此组件接受match、location、history
* <Route path="/home" component={Home} />
<Route render> - 适用于内联渲染,不会产生重复装载问题
* <Route path="/home" render={() => <h1>Home</h1} />
<Route children> -
2、props分别是: match、location、history
<Route path="/:id" component={ListBasic}></Route> // 参数传给子组件
this.props.match.params.id // 获取参数值
3、path: 路由路径
exact: true,表示独一无二的路由
// 如果不加exact, "/" 时加载main, "/login" 会显示main和login两个组件,如果加了exact在"/"路由时只会显示main组件
<div style={{ height: "500px", backgroundColor: "#ccc"}}>
<Route path="/" exact component={Main} />
<Route path="/login" component={Login} />
<Route path="/todoList" component={TodoList} />
</div>
strict: true,如果path为'/one/'将不能匹配'/one',但可以匹配'/one/two'
五、路由跳转
1、Link、NavLink
<Link to="/course" />
<Link to={{
pathname: '/course',
search: '?sort=name',
state: { price: 18 }
}} />
// 给导航使用的
<NavLink
to="/about"
activeStyle={{ color: 'green', fontWeight: 'bold' }}
>MyBlog</NavLink>
2、JS跳转
export default class SelectCard extends Component {
constructor(props){
super(props);
}
goHomePage(){
this.props.history.push('/main'); // 跳转
}
render(){
return {
<div>
<button onClick={this.goHomePage.bind(this)}>跳转</button>
</div>
}
}
}
/** 注意如果使用redux子组件会取不到this.props.history **/
解决方法: 在子组件中
import PropTypes from 'prop-types'
子组件名.contextTypes = {
router: PropTypes.object.isRequired
}
console.log( this.context.router.history.push('/') );
六、<switch> 只渲染出第一个与当前访问地址匹配的 <Route> 或 <Redirect>
// v3
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route path='about' component={About} />
<Route path='contact' component={Contact} />
</Route>
v4中使用<switch>来取代<IndexRouter>, 当react渲染时switch下第一个子<route>会被渲染
// v4
const App = () => (
<Switch>
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
<Route path='/contact' component={Contact} />
</Switch>
)
七、添加图像、字体和文件
组件中加载图片
import logo from './logo.png'; 导入图片
<img src={logo} alt="Logo" />;
css中加载图片
.logo{
background-image: url('./logo.png');
}
八、Redirect重定向 和 未匹配路由跳转到404
// 跳404用法
render() {
return (
<Router>
<div className="main-container">
<Route path="/main" component={Main} />
<Route component={Page404}/> // 没有定义path就是没有路径匹配时
</div>
</Router>
)
}
// Redirect 用法不渲染组件直接重定到其它页面
render() {
if(!this.state.logined){
return (
<Redirect to="/todoList" />
)
}
return (
<div>
这里是Login组件
</div>
)
}
九、动态路由
1、路由变量
定义变量: <Route path="/:msg" component={Message} />
获取变量: props.match.params.定义的名
<Route path="/hello/:name"> // 匹配 /hello/michael 和 /hello/ryan
<Route path="/hello(/:name)"> // 匹配 /hello, /hello/michael 和 /hello/ryan
<Route path="/files/*.*"> // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
Example:
class Message extends Component {
render(props){
return (
<div>
// 这里this.props.params.msg 接收的是to的名字
<h1>{this.props.match.params.jumpUrl || 'hello'}</h1>
<Links />
</div>
)
}
}
const Links = () =>{
<nav>
<Link to="/">Hello</Link>
<Link to="/yong">Yong</Link>
<Link to="/feng">Feng</Link>
</nav>
}
class ParamsRoute extends Component {
render() {
return (
<Router history={hashHistory}>
<Route path="/(:msg)" component={Message} />
</Router>
);
}
}
export default ParamsRoute;
2、query: 获取URL中的参数
1) 获取参数
http://localhost:8080/#/?message=ssssss
const Page = (props) =>
<div>
<h1>{props.location.query.message || 'Hello'}</h1> // props.location.query.message输出 ssssss
</div>
2) <Link>请求时带参数
const Page = (props) =>
<div>
<h1>{props.location.query.message || 'Hello'}</h1>
</div>
const Links = () =>
<nav>
<Link to={{ pathname: "/", query: {message: "ssssss"} }} />
</nav>
3) js中请求参数
goToMessage(){
that.props.history.push({
pathname : '/success',
query : { messageTitle: '充值成功', messageContent: '请取您的充值单请取您的充值单请取您的充值单'}
})
}
十、路嵌套和展示
// v2/3版本 就是一个路由配置文件,在放子路由的地方使用
<div>
{ this.props.childre } // 加载子路由的位置
</div>
// v4版本
// router.jsx
export default class Index extends Component {
render() {
return (
<Router>
<Switch>
<Layout />
</Switch>
</Router>
)
}
}
// layout.jsx
export default class Layout extends Component {
render() {
let menuHtml = () => {
const menuItem = [];
this.state.menuList.forEach(function(menu, idx, arr){
menuItem.push(
<li>
<Link to={menu.path}>{menu.title}</Link>
</li>
)
})
return menuItem
}
return (
<div>
<header style={{height: "100px"}}>
菜单: { menuHtml() }
</header>
<main style={{ height: "500px", backgroundColor: "#ccc"}}>
// 这下面都是子路由的展示位置
<Route path="/" exact component={Main} />
<Route path="/login" component={Login} />
<Route path="/todoList" component={TodoList} />
<Route component={Page404}></Route> // 注: 如果没有匹配路由指到到404页面, 不需要使用Redirect
</main>
</div>
)
}
}
// login.jsx
export default class Login extends Component {
constructor(props){
super(props);
this.state = {
logined: true
}
}
render() {
/* 这里可以不渲染组件直接重定到其它页面 */
if(!this.state.logined){
return (
<Redirect to="/todoList" />
)
}
return (
<div>
这里是Login组件
</div>
)
}
}
https://www.jianshu.com/p/7bb4c1a0530d
https://www.jianshu.com/p/548674270455
十一、withRouter
withRouter是专门用来处理数据更新问题,否则可能会出现路由地址改变但页面没有相应改变的bug
import React, { Component } from 'react'
import { withRouter } from 'react-router'
import { Route, Redirect } from 'react-router-dom'
class AuthRouter extends Component {
render() {
const { component: Component, ...rest } = this.props
const isLogged = sessionStorage.getItem("isLogin") === "1" ? true : false;
return (
<Route {...rest} render={props => {
return isLogged
? <Component {...props} />
: <Redirect to="/login" />
}} />
)
}
}
export default withRouter(AuthRouter);
dva+react+Ant 蚂蚁金服脚手架
单独加载ant UI框架,也可以使用dva-cli蚂蚁提供的脚手架,支持IE9及以上版本
一、单独添加ant
$ cnpm i antd --save
import 'antd/dist/antd.css'; // 引入样式
import { DatePicker } from 'antd'; // 这种方法的引用必须要添加babel-plugin-import的按需加载组件
ReactDOM.render(<DatePicker />, mountNode);
二、按需加载插件 babel-plugin-import
$ cnpm i babel-plugin-import --save
.babelrc添加参数:
{
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }] // `style: true` 会加载 less 文件
]
}
三、dva-cli安装
$ cnpm i dva-cli
$ dva new [项目名] && cd [项目名] // 创建项目
$ cnpm install antd babel-plugin-import --save // 安装 ant 和 babel插件(用来按需加载 antd 的脚本和样式的)
.webpackrc文件加参数
{
"extraBabelPlugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}
四、运行
$ npm start // 生产环境运行
$ npm run build // 打包项目,发布线上环境在Dist目录下生成静态文件,js、css压缩
五、redux的使用
有两个目录,models和components, model来定义state和action的,components来编写组件
dva提供conect方法,将model和component串联起来
import { connect } from 'dva';
const Products = ({ dispatch, products }) => { ... }
export default connect(({ products }) => ({
products,
}))(Products);
六、配置
1、 .roadhogrc.mock.js 用于mock数据的配置
export default {
// 支持值为 Object 和 Array
'GET /api/users': { users: [1,2] },
// GET POST 可省略
'/api/users/1': { id: 1 },
// 支持自定义函数,API 参考 express@4
'POST /api/users/create': (req, res) => { res.end('OK'); },
};
2、.webpackrc
{
"extraBabelPlugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
],
"entry": "src/index.js", // 可以配置webpack的选项,参数见面下roadhog的文档连接
"proxy": { // 设置代理
"/api": {
"target": "http://jsonplaceholder.typicode.com/",
"changeOrigin": true,
"pathRewrite": { "^/api" : "" }
}
}
}
3、设置端口
默认是8000,可以在package.json中设置
"scripts": {
"start": "PORT=3000 roadhog server", // windowns设置 set PORT=3000&&roadhog dev
}
4、public目录会在build的copy到dist目录下,存放一些静态文件
https://github.com/sorrycc/blog/issues/18 // dva
https://github.com/sorrycc/roadhog/blob/master/README_zh-cn.md // roadhog
七、fatch请求
dva-cli中utils目录中request.js中定义了一个通过fatch来发ajax请求的方法
业务中调用:
function IndexPage() {
var getUser = () => {
Request('/api/posts', {method: 'GET'})
.then((data)=>{
debugger;
})
}
getUser()
return (
<div className={styles.normal}>
...
</div>
);
}
exports default IndexPage;
收集组件
1、react-transition-group - 页面切换过渡效果
https://github.com/reactjs?page=2
| https://facebook.github.io/create-react-app/ // create-react-app 官网
| https://react-guide.github.io/react-router-cn/ // React-router 中文网
| https://reacttraining.com/react-router/web/example/basic // 官方示例**
| https://www.jianshu.com/p/25e9ba1ebafb // react源码分析
| https://github.com/YutHelloWorld/Blog/issues/4 // v2、3迁移v4
| https://www.jianshu.com/p/e0a0ed6c3b8a // 路由跳转登录验证
| https://www.jianshu.com/p/e3adc9b5f75c/
| https://segmentfault.com/a/1190000009349377 // router ^4
| https://github.com/reactjs/react-router-redux
国内查看评论需要代理~