目录javascript
在建立一个vue项目的时候, 1.在index.js文件中引入react模块,引入在须要的节点所须要的组件 import React from 'react'; // 必需要引入的模块 import ReactDOM from 'react-dom'; // 给某一个DOM节点渲染时用到,它是从react中分离出来的 import App from '@/components/App'; // React的一个组件 // 将虚拟的组件渲染到视图中 // 组件名字必须是大写,若是是小写的话它会认为是html标签,组件的文件名也建议大写 ReactDom.render ( // render是一个钩子函数 <APP />, document.getElementById('root') //表示的是组件放到哪一个节点中 ) 2.在components文件夹下,编写组件App.jsx import React from 'react' /** 在react中开发组件模式: > ES6 class类写法 类组件 > ES6 箭头函数写法 函数式组件 ----无状态组件 */ // return() ()内部的代码写的是虚拟Dom,符合jsx语法 //class 类: class App extends React.Component { render () { return ( <div>hello react</div> ) } } export default App; // 函数式组件 const App = () => { return ( <div> hello function</div> ) } 如何选择类组件仍是函数式组件? 若是一个组件须要有状态,那么必定不要写函数式组件,函数式组件又会被成为 无状态组件,函数式组件通常会使用为UI组件(只负责渲染视图,数据都来源于父组件)---- 在react16.8的时候要注意一下(有另外一种说法)
子类必须在constructor方法中调用super方法,不然新建实例时会报错。这是由于子类本身的this对象,必须先经过父类的构造函数完成塑造,获得与父类一样的实例属性和方法,而后再对其进行加工,加上子类本身的实例属性和方法。若是不调用super方法,子类就得不到this对象。css
经常使用的react的生命周期钩子函数html
constructor() 经过给 this.state 赋值对象来初始化内部 state。为事件处理函数绑定实例vue
render() 只要是组件就必须有的java
componentDidMount() 若是须要请求数据,若是须要DOM操做,实例化操做node
componentDidUpdate() 若是须要DOM操做,实例化操做react
componentWillUnmount() 若是须要清除定时器,计时器,实例对象webpack
jsx它既不是一个字符串也不是一个HTML,是javascript的语法拓展。jsx能够生成react中的元素,组件就是由元素组成的。 jsx的特性属性,在属性中嵌入javascript代码时,在大括号外面不用加引号 jsx能够防止javascript脚本攻击,由于在渲染的时候,它会先将代码转化成字符串。
props是只读的,它用在组件与组件之间 能够把props理解为从外部传入组件内部的数据。因为React是单向数据流,因此props基本上也就是从服父级组件向子组件传递的数据。 state可读可写,它用在组件内 它就是数据的状态
state
是组件本身管理数据,控制本身的状态,可变;props
是外部传入的数据参数,不可变;state
的叫作无状态组件,有state
的叫作有状态组件;props
,少用state
。也就是多写无状态组件。项目目录树:入口找布局,布局找页面,页面找的是组件,组价中能够找子组件ios
在入口文件中配置路由es6
import { BrowserRouter as Router, Switch, Route } from react-router-dom import App from '@/layout/App' import Detail from '@/layout/Detail' <Router> <Switch> <Route path="/detail" component={ Detail } /> <Route path="/" component={ App } /> </Switch> </Router>
在布局文件中配置路由:带参数
<Switch> <Route path="/detail/order" component={ Order }/> <Route path="/detail/:id" component={ Detail }/> </Switch>
在布局文件中配置路由:不带参数
import Home from '@/view/Home' import Kind from '@/view/Kind' import Cart from '@/view/Cart' import User from '@/view/User' import { Route, Switch, NavLink, Redirect } from 'react-router-dom' <Switch> <Route path= '/home' component={ Home } /> <Route path= '/kind' component={ Kind } /> <Route path= '/cart' component={ Cart } /> <Route path= '/user' component={ User } /> <Redirect to ='/home' /> //重定向 </Switch> <NavLink to="/home"><NavLink> //点击跳转,若是有样式变化用NavLink //<Link to={ "/detail/id=" + item.id }><Link> //没有样式变化的跳转,用Link
注:路由的查找是从上到下的,因此path = "/"必定要放在最下面,不然就直接进入path = "/"页面,找不到path="/detail" 页面
布局文件不写具体页面,子组件数据由页面传递,因此子组件中能够用函数式组件
注:详情页跳转时path="/detail/:id"
重定向和404页面
import NoMatch from '@/view/NoMatch'; <Redirect exact from = '/' to ='/home' /> //exact表示只有“/”才能重定向到“/home” <Route component = { NoMatch } />
1.利用{...this.props}将父组件中的值传递到子组件中,在子组件中{ }使用
2.结合相似vue的插槽完成自定中介部分的内容
封装Header组件
//<Header>组件 import React from 'react' export default (props) => { console.log(props) const { left, right, content, onLeft, onRight } = props //从父组件中传过来的值 return ( <ul> <li onClick = { () => { if(props.match.path === '/home') { return } props.history.goBack() // onLeft() } }> {left} </li> <li>{props.children? props.children : content? content : ''}</li> <li onClick = { () => { onRight() }}>{right}</li> </ul> ) }
//父组件中引用子组件的地方 <Header left = "返回" content = "搜索" right = "扫一扫" onLeft = {() => { // this.props.history.goBack() console.log('返回') }} onRight = { () => { console.log('扫一扫') }} {...this.props} > <div className="seach">请输入搜索的内容</div> </Header>
安装 ant UI库文件
cnpm i antd-mobile -S
在index页面中引入文件(引入 Promise 的 fallback 支持 (部分安卓手机不支持 Promise))
将此段代码直接替换 <meta name="viewport" content="width=device-width, initial-scale=1" /> 替换为: <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script> <script> if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } if(!window.Promise) { document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>'); } </script>
在config/webpack.config.js中添加UI库的配置。(因为咱们用到是react脚手架将config独立出来了,没有babel-plugin-文件)
npm i babel-plugin-import -D
在第357行,粘贴 ["import", { libraryName: "antd-mobile", style: "css" }] // `style: true` 会加载 less 文件
基本配置完成,接下来须要哪一个组件引入便可
ReduX并不独属于React,他是js的状态管理容器,在vue中也能用,只是在react中用起来更好,react-redux是属于react的
在store.js页面中 -》 index.js页面引入store监听事件 -》在App页面disptch触发事件改变store中的值
//在store->index.js文件中配置状态管理器 import { creatStore } from 'redux'; const reducer = (state = { bannerlist: [], prolist:[] },action) => { const { type, data } = action; switch (type) { case 'CHANGE_BANNER_LIST': return Object.assign({}, state, {bannerlist:data}) case 'CHANGE_PRO_LIST': return Object.assign({}, state, { prolist: data }) default: return state; } } const store = creatStore(reducer); export default store;
//在index.js入口文件中监听状态管理器的变化 import React from 'react' import ReactDOM from 'react-dom' import App from './App' import store from './store' function renderFn(){ ReactDOM.render( <App />, document.getElementById('root') ) } renderFn(); // 若是检测到状态管理器中有变化触发 store.subscribe(renderFn)
//在须要使用状态管理器数据的页面中(App.jsx)请求数据,改变状态状态管理器中的数据 import React, { Component } from 'react'; import axios from 'axios'; import store from './store' export default class extends Component { componentDidMount () { axios.get('https://www.daxunxun.com/banner').then(res => { console.log(res.data,'data'); console.log(store,'store'); store.dispatch({ type: 'CHANGE_BANNER_LIST', data: res.data }) }) axios.get('https://www.daxunxun.com/douban').then(res => { store.dispatch({ type: 'CHANGE_PRO_LIST', data: res.data }) }) } render () { console.log(store.getState(),'getState') const { bannerlist, prolist } = store.getState(); return ( <div> <h1>状态管理器</h1> <ul> { prolist.map(item => ( <li key = { item.id }> { item.title } </li> )) } </ul> </div> ) } }
容器组件只负责业务逻辑的处理,
UI组件只负责数据的渲染
将App.jsx文件拆分红App.jsx和UI.jsx,前者负责写业务逻辑,后者负责渲染数据
//在index.js入口文件中改成 ReactDOM.render( <Provider store = { store }> <App /> </Provider>, document.getElementById('root') )
//在App.jsx中写业务 逻辑 import { connect } from 'react-redux' import axios from 'axios'; import UI from './UI' // ui组件须要的状态 const mapStateToProps = (state) => { return { bannerlist: state.bannerlist, prolist: state.prolist } } // ui组件的业务逻辑 const mapDispatchToProps = (dispatch) => { return { getBannerlist () { axios.get('https://www.daxunxun.com/banner').then(res =>{ dispatch({ type: 'CHANGE_BANNER_LIST', data: res.data }) }) }, getProlist () { axios.get('https://www.daxunxun.com/douban').then(res => { dispatch({ type: 'CHANGE_BANNER_LIST', data: res.data }) }) } } } const App = connect(mapStateToProps, mapDispatchToProps)(UI) export default App;
//在UI组件中渲染数据 import React, { Component } from 'react'; export default class extends Component { componentDidMount () { this.props.getBannerlist(); this.props.getProlist(); } render () { // console.log(store.getState(),'getState') const { bannerlist, prolist } = this.props; return ( <div> <h1>状态管理器</h1> <ul> { prolist.map(item => ( <li key = { item.id }> { item.title } </li> )) } </ul> </div> ) } }
将状态管理器拆分到每一个页面,而后在store->index文件中配置,单首创建一个action文件,将异步请求数据单拎出来。
// action页面写异步请求 import axios from 'axios'; export default { getBannerlist (dispatch) { axios.get('https://www.daxunxun.com/banner').then(res => { dispatch({ type: 'CHANGE_BANNER_LIST', data: res.data }) }) } }
//状态管理器的入口文件 import { createStore, combineReducers, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import home from './home' import kind from './kind' const reducer = combineReducers({ home, kind }) // applyMiddleware 函数的做用就是对 store.dispatch 方法进行加强和改造,使得在发出 Action 和执行 Reducer 之间添加其余功能。 //引入thunk插件后,咱们能够在actionCreators内部编写逻辑,处理请求结果。而不仅是单纯的返回一个action对象。 const store = createStore(reducer, applyMiddleware(thunk)); export default store;
//状态管理器单个页面 const reducer = (state = { bannerlist: [], prolist: [] }, action) => { const { type, data } = action; switch (type) { case 'CHANGE_BANNER_LIST': return Object.assign({}, state, {bannerlist: data}); case 'CHANGE_PRO_LIST': return Object.assign({}, state, {prolist: data}); default: return state; } } export default reducer;
cnpm / npm i create-react-app -g
create-react-app myapp
使用npx直接建立项目
npx是一种在npm中安装工具,也能够被单独的下载使用
在npm 5.2.0 的时候发现会买一送一,自动安装了npx。
npx create-react-app myapp
(npm 的版本必须在5.2.0以上)
运行 npm run eject 抽离配置文件
修改package.json ,配置dev指令
配置src文件夹的别名 @
cnpm i node-sass -D
cnpm i react-router-dom@4 redux react-redux redux-thunk axios antd-mobile -S
在src下面建立main.scss在首页中引入
引入路由文件 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
引入状态管理器文件 import store from './store';
配置文件 import { Provider } from 'react-redux';
全局引入组件库css文件 import 'antd-mobile/dist/antd-mobile.css';
若是在render中使用console.log,因为react的生命周期中,在其初始化阶段会执行一次render初次渲染,在运行时阶段执行一次render渲染数据,因此会执行2次,也就打印了2次。
{ ...this.props } 将父组件的路由信息传给组件。 this.props主要包含:history属性、location属性、match属性
由于当咱们输入网址的时候,它默认匹配“/”进入布局页面,若是你网址不对不算进入此项目,输入正确的地址后即进入项目,默认“/”进入布局页面,进入布局页面咱们把它重定向到“/home”做为首页,若是输入其余匹配不到的就404页面。其余布局页面不用写,由于咱们进入首页后,其余页面都是经过页面间跳转的,不须要手动在网址上输入。