目錄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頁面。其餘佈局頁面不用寫,由於咱們進入首頁後,其餘頁面都是經過頁面間跳轉的,不須要手動在網址上輸入。