React 構建用戶界面的JavaScript庫,主要用於構建UI界面。Instagram,2013年開源。javascript
1、經過script引入使用,僅用於學習調試使用css
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
二、經過react的腳手架,建立項目進行開發,部署html
1. 安裝腳手架Create React App。 cnpm install -g create-react-app 2. 建立項目 create-react-app 01reactapp(項目名稱能夠自定義)
let h1 = <h1>helloworld</h1>; 使用JSX的寫法,能夠建立JS元素對象 注意:JSX元素對象,或者組件對象,必須只有1個根元素(根節點)
案例使用:vue
//實現頁面時刻的顯示 function clock(){ let time = new Date().toLocaleTimeString() let element = ( <div> <h1>如今的時間是{time} </h1> <h2>這是副標題</h2> </div> ) let root = document.querySelector('#root'); ReactDOM.render(element,root) } clock() setInterval(clock,1000)
函數式組件渲染java
function Clock(props){ return ( <div> <h1>如今的時間是{props.date.toLocaleTimeString()} </h1> <h2>這是函數式組件開發</h2> </div> ) } function run(){ ReactDOM.render( <Clock date={new Date()} />, document.querySelector('#root') ) } setInterval(run,1000)
優勢:react
注意:es6
案例vuex
import React from 'react'; import ReactDOM from 'react-dom'; import './App.css' let time = new Date().toLocaleTimeString() let str = '當前時間是:' let element = ( <div> <h1>helloworld</h1> <h2>{str+time}</h2> </div> ) console.log(element) let man = '發熱'; let element2 = ( <div> <h1>今天是否隔離</h1> <h2>{man=="發熱"?<button>隔離</button>:"躺牀上"}</h2> </div> ) //let man = '發熱'; let element4 = ( <div> <span>橫着躺</span> <span>豎着躺</span> </div> ) man = '正常' let element3 = ( <div> <h1>今天是否隔離</h1> <h2>{man=="發熱"?<button>隔離</button>:element4}</h2> </div> ) let color = 'bgRed' let logo = 'https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png' //HTML的樣式類名要寫className,由於class在js當中是關鍵詞 let element5 = ( <div className={color}> <img src={logo} /> 紅色的背景顏色 </div> ) ReactDOM.render( element5, document.getElementById('root') )
let exampleStyle = { background:"skyblue", borderBottom:"4px solid red", 'background-image':"url(https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png)" }
3.多個類共存的操做npm
let element2 = ( <div> <h1 className={"abc "+classStr}>helloworld</h1> </div> ) let classStr2 = ['abc2','redBg2'].join(" ") let element3 = ( <div> {/* 這裏寫註釋 */} <h1 className={classStr2} style={exampleStyle}>helloworld</h1> </div> )
4.註釋json
必須在括號的表達式內書寫,不然報錯:{/* 這裏寫註釋 */}
函數式組件與類組件的區別和使用,函數式比較簡單,通常用於靜態沒有交互事件內容的組件頁面。類組件,通常又稱爲動態組件,那麼通常會有交互或者數據修改的操做。
//函數式組件 function Childcom(props){ console.log(props) let title = <h2>我是副標題</h2> let weather = props.weather //條件判斷 let isGo = weather=='下雨' ?"不出門":"出門" return ( <div> <h1>函數式組件helloworld</h1> {title} <div> 是否出門? <span>{isGo}</span> </div> </div> ) }
2.類組件
//類組件定義 class HelloWorld extends React.Component{ render(){ console.log(this) return ( <div> <h1>類組件定義HELLOWORLD</h1> <h1>hello:{this.props.name}</h1> <Childcom weather={this.props.weather} /> </div> ) } }
3.複合組件:組件中又有其餘的組件,複合組件中既能夠有類組件又能夠有函數組件。
import React from 'react'; import ReactDOM from 'react-dom'; import './04style.css'; //函數式組件 function Childcom(props){ console.log(props) let title = <h2>我是副標題</h2> let weather = props.weather //條件判斷 let isGo = weather=='下雨' ?"不出門":"出門" return ( <div> <h1>函數式組件helloworld</h1> {title} <div> 是否出門? <span>{isGo}</span> </div> </div> ) } //類組件定義 class HelloWorld extends React.Component{ render(){ console.log(this) //返回的都是JSX對象 return ( <div> <h1>類組件定義HELLOWORLD</h1> <h1>hello:{this.props.name}</h1> <Childcom weather={this.props.weather} /> </div> ) } } // ReactDOM.render( // <Childcom weather="出太陽" />, // document.querySelector('#root') // ) ReactDOM.render( <HelloWorld name="老陳" weather="下雨" />, document.querySelector('#root') )
至關於VUE的DATA,可是使用方式跟VUE不一致。
父傳遞給子組件數據,單向流動,不能子傳遞給父。
props的傳值,能夠是任意的類型。
Props能夠設置默認值
HelloMessage.defaultProps = { name:」老陳」,msg:「helloworld」 }
注意:props能夠傳遞函數,props能夠傳遞父元素的函數,就能夠去修改父元素的state,從而達到傳遞數據給父元素。
父傳參給子
//在父元素中使用state去控制子元素props的從而達到父元素數據傳遞給子元素 class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isActive:true } //綁定事件 this.changeShow = this.changeShow.bind(this) } render(){ return ( <div> <button onClick={this.changeShow}>控制子元素顯示</button> <ChildCom isActive={this.state.isActive} /> </div> ) } changeShow(){ this.setState({ isActive:!this.state.isActive }) } } class ChildCom extends React.Component{ constructor(props){ super(props) } render(){ let strClass = null; if(this.props.isActive){ strClass = ' active' }else{ strClass = "" } strClass = this.props.isActive?" active":""; return ( <div className={"content"+strClass}> <h1>我是子元素</h1> </div> ) } }
子傳參給父
class Parent extends React.Component { constructor(props) { super(props) this.state = { childData: null } } render() { return ( <div> <h1>子元素傳遞給父元素的數據:{this.state.childData}</h1> {/* 將設置參數的方法經過props傳給子元素 */} <Child setChildData={this.setChildData}/> </div> ) } setChildData=(data)=>{ this.setState({ childData:data }) } } class Child extends React.Component{ constructor(props){ super(props) this.state={ msg:"helloworld" } } render(){ return( <div> <button onClick={this.senData}>傳參給父元素</button> //使用ES6,能夠直接在按鈕的事件中寫箭頭函數傳參 <button onClick={()=>{this.props.setChildData("666")}}>傳參給父元素</button> //不使用ES6, <button onClick={function(e){this.props.setChildData("666")}.bind(this)}>傳參給父元素</button> </div> ) } //不綁定事件能夠直接使用箭頭函數 senData=()=>{ 從父元素傳過來的props裏面的方法傳遞參數 this.props.setChildData(this.state.msg) } }
事件
特色:
一、react事件,綁定事件的命名,駝峯命名法。
二、{},傳入1個函數,而不是字符串
<button onClick={this.sendData}>傳遞helloworld給父元素</button>
事件對象:React返回的事件對象是代理的原生的事件對象,若是想要查看事件對象的具體值,必須之間輸出事件對象的屬性。
注意:
原生,阻止默認行爲時,能夠直接返回return false;
React中,阻止默認必須e.preventDefault();
React事件傳參數
{/* 使用ES6箭頭函數傳遞多個參數 */} <button onClick={(e)=>{this.parentEvent1('msg:helloworld',e)}}>提交</button> {/* //不使用ES6箭頭函數傳遞多個參數的方式 */} <button onClick={function(e){this.parentEvent1('不使用es6,msg:helloworld',e)}.bind(this)}>提交</button>
條件渲染
一、直接經過條件運算返回要渲染的JSX對象
二、經過條件運算得出jsx對象,在將JSX對象渲染到模板中。
案例1
function UserGreet(props){ return (<h1>歡迎登錄</h1>) } function UserLogin(props){ return (<h1>請先登陸</h1>) } class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isLogin:true } } render(){ if(this.state.isLogin){ return (<UserGreet></UserGreet>) }else{ return (<UserLogin></UserLogin>) } } }
案例2
function UserGreet(props){ return (<h1>歡迎登錄</h1>) } function UserLogin(props){ return (<h1>請先登陸</h1>) } class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isLogin:false } } render(){ let element = null; if(this.state.isLogin){ element = <UserGreet></UserGreet>; }else{ element = (<UserLogin></UserLogin>); } return ( <div> <h1>這是頭部</h1> {element} <h1>這是三元運算符的操做</h1> {this.state.isLogin?<UserGreet></UserGreet>:<UserLogin></UserLogin>} <h1>這是尾部</h1> </div> ) } }
列表渲染
將列表內容拼裝成數組放置到模板中。將數據拼裝成數組的JSX對象。
使用數組的map方法,對每一項數據按照JSX的形式進行加工,最終獲得1個每一項都是JSX對象的數組,在將數組渲染到模板中。
Key值須要放置到每一項中。
案例1
class Welcome extends React.Component{ constructor(props){ super(props) this.state = { list:[ { title:"第一節 React事件", content:"事件內容" }, { title:"第二節 React數據傳遞", content:"數據傳遞內容", }, { title:"第三節 條件渲染", content:"條件渲染內容", } ] } } render(){ let listArr = []; for(let i=0;i<this.state.list.length;i++){ let item = ( <li> <h3>{this.state.list[i].title}</h3> <p>{this.state.list[i].content}</p> </li> ) listArr.push(item) } return ( <div> <h1> 今天課程內容 </h1> <ul> {listArr} <li> <h3>這是標題</h3> <p>內容</p> </li> </ul> </div> ) } }
案例2
function ListItem(props){ return ( <li> <h3>{props.index+1}:listItem:{props.data.title}</h3> <p>{props.data.content}</p> </li> ) } class ListItem2 extends React.Component{ constructor(props){ super(props) } render(){ return ( <li onClick={(event)=>{this.clickEvent( this.props.index, this.props.data.title, event )}}> <h3>{this.props.index+1}:listItem:{this.props.data.title}</h3> <p>{this.props.data.content}</p> </li> ) } clickEvent=(index,title,event)=>{ alert((index+1)+"-"+title) } } class Welcome extends React.Component{ constructor(props){ super(props) this.state = { list:[ { title:"第一節 React事件", content:"事件內容" }, { title:"第二節 React數據傳遞", content:"數據傳遞內容", }, { title:"第三節 條件渲染", content:"條件渲染內容", } ] } } render(){ let listArr = this.state.list.map((item,index)=>{ return ( <ListItem2 key={index} data={item} index={index}></ListItem2> ) }) return ( <div> <h1> 今天課程內容 </h1> <ul> {listArr} <li> <h3>這是標題</h3> <p>內容</p> </li> </ul> <h1>複雜沒有用組件完成列表</h1> <ul> { this.state.list.map((item,index)=>{ return ( <li key={index} onClick={(event)=>{this.clickFn(index,item.title,event)}}> <h3>{index+1}-複雜-{item.title}</h3> <p>{item.content}</p> </li> ) }) } </ul> </div> ) } clickFn=(index,title,event)=>{ alert((index+1)+"-clickFn-"+title) } }
生命週期便是組件從實例化到渲染到最終從頁面中銷燬,整個過程就是生命週期,在這生命週期中,咱們有許多能夠調用的事件,也俗稱爲鉤子函數
生命週期的3個狀態:
Mounting:將組件插入到DOM中
Updating:將數據更新到DOM中
Unmounting:將組件移除DOM中
生命週期中的鉤子函數(方法,事件)
CompontWillMount :組件將要渲染,AJAX,添加動畫前的類
CompontDidMount:組件渲染完畢,添加動畫
compontWillReceiveProps:組件將要接受props數據,查看接收props的數據什麼
ShouldComponentUpdate:組件接收到新的state或者props,判斷是否更新。返回布爾值
CompontWillUpdate:組件將要更新
ComponentDidUpdate:組件已經更新
ComponentwillUnmount:組件將要卸載
組建中寫入內容,這些內容能夠被識別和控制。React須要本身開發支持插槽功能。
原理:
組件中寫入的HTML,能夠傳入到props中。
組件中的HTML內容直接所有插入
組件中的HTML內容直接所有插入
class ParentCom extends React.Component{ render(){ console.log(this.props) return ( <div> <h1>組件插槽</h1> {this.props.children} </div> ) } }
組件中根據HTML內容的不一樣,插入的位置不一樣。
import React from 'react'; import ReactDOM from 'react-dom'; class ParentCom extends React.Component{ render(){ console.log(this.props) return ( <div> <h1>組件插槽</h1> {this.props.children} <ChildCom> <h1 data-position="header">這是放置到頭部的內容</h1> <h1 data-position="main">這是放置到主要的內容</h1> <h1 data-position="footer">這是放置到尾部的內容</h1> </ChildCom> </div> ) } } class ChildCom extends React.Component{ render(){ let headerCom,mainCom,footerCom; this.props.children.forEach((item,index)=>{ if(item.props['data-position']==='header'){ headerCom = item }else if(item.props['data-position']==='main'){ mainCom = item }else{ footerCom = item } }) return ( <div> <div className="header"> {headerCom} </div> <div className="main"> {mainCom} </div> <div className="footer"> {footerCom} </div> </div> ) } } class RootCom extends React.Component{ constructor(props){ super(props) //console.log(props) this.state = { arr:[1,2,3] } } render(){ return ( <ParentCom> <h2 data-name="a" data-index={this.state.arr[0]}>子組件1</h2> <h2 data-name="b" data-index={this.state.arr[1]}>子組件2</h2> <h2 data-name="c" data-index={this.state.arr[2]}>子組件3</h2> </ParentCom> ) } } ReactDOM.render( <RootCom></RootCom> , document.querySelector("#root") )
根據不一樣的路徑,顯示不一樣的組件(內容);React使用的庫react-router-dom;
安裝
Cnpm install react-router-dom --save
ReactRouter三大組件:
Router:全部路由組件的根組件(底層組件),包裹路由規則的最外層容器。
屬性:basename->設置跟此路由根路徑,router能夠在1個組件中寫多個。
Route:路由規則匹配組件,顯示當前規則對應的組件
Link:路由跳轉的組件
注意:若是要精確匹配,那麼能夠在route上設置exact屬性。
Router使用案例
import React from 'react'; //hash模式 //import {HashRouter as Router,Link,Route} from 'react-router-dom' //history模式/後端匹配使用 import {BrowserRouter as Router,Link,Route} from 'react-router-dom' function Home(){ return ( <div> <h1>admini首頁</h1> </div> ) } function Me(){ return ( <div> <h1>admin我的中心</h1> </div> ) } function Product(){ return ( <div> <h1>admin產品頁面</h1> </div> ) } class App extends React.Component{ render(){ return ( <div id="app"> {/* <div>全部頁面普通內容</div> */} <Router> <Route path="/" exact component={()=>(<div>首頁</div>)}></Route> <Route path="/me" component={()=>(<div>me</div>)}></Route> <Route path="/product" component={()=>(<div>product</div>)}></Route> </Router> <Router> {/* <div className="nav"> <Link to="/">Home</Link> <Link to="/product">Product</Link> <Link to="/me">我的中心</Link> </div> */} <Route path="/admin/" exact component={Home}></Route> <Route path="/admin/product" component={Product}></Route> <Route path="/admin/me" exact component={Me}></Route> </Router> </div> ) } } export default App
Link組件能夠設置to屬性來進行頁面的跳轉,to屬性能夠直接寫路徑的字符串,也能夠經過1個對象,進行路徑的設置,如
render(){ let meObj = { pathname:"/me",//跳轉的路徑 search:"?username=admin",//get請求參數 hash:"#abc",//設置的HASH值 state:{msg:'helloworld'}//傳入組件的數據 }; return ( <div id="app"> <Router> <div className="nav"> <Link to="/">Home</Link> <Link to="/product">Product</Link> <Link to={ meObj }>我的中心</Link> </div> <Route path="/" exact component={Home}></Route> <Route path="/product" component={Product}></Route> <Route path="/me" exact component={Me}></Route> </Router> </div> ) }
Link的replace屬性:點擊連接後,將新地址替換成歷史訪問記錄的原地址。
動態路由實現:
import React from 'react'; //hash模式 //import {HashRouter as Router,Link,Route} from 'react-router-dom' //history模式/後端匹配使用 import {BrowserRouter as Router,Link,Route} from 'react-router-dom' function Home(){ return ( <div> <h1>admini首頁</h1> </div> ) } function Me(props){ console.log(props) return ( <div> <h1>admin我的中心</h1> </div> ) } function Product(){ return ( <div> <h1>admin產品頁面</h1> </div> ) } function News(props){ console.log(props) return ( <div> 新聞頁,新聞id:{props.match.params.id} </div> ) } class App extends React.Component{ render(){ let meObj = { pathname:"/me",//跳轉的路徑 search:"?username=admin",//get請求參數 hash:"#abc",//設置的HASH值 state:{msg:'helloworld'}//傳入組件的數據 }; return ( <div id="app"> <Router> <div className="nav"> <Link to="/">Home</Link> <Link to="/product">Product</Link> <Link to={ meObj } replace>我的中心</Link> <Link to="/news/4568789">新聞頁</Link> </div> <Route path="/" exact component={Home}></Route> <Route path="/product" component={Product}></Route> <Route path="/me" exact component={Me}></Route> <Route path="/news/:id" component={News}></Route> </Router> </div> ) } } export default App
若是訪問某個組件時,若是有重定向組件,那麼就會修改頁面路徑,使得頁面內容顯示爲所定向路徑的內容
用例:
function LoginInfo(props){ //props.loginState = 'success'; //props.loginState = "fail" console.log(props) if(props.location.state.loginState === 'success'){ return <Redirect to="/admin"></Redirect> }else{ return <Redirect to="/login"></Redirect> } }
讓switch組件內容的route只匹配1個,只要匹配到了,剩餘的路由規則將再也不匹配
class App extends React.Component{ render(){ return ( <div> <Router> <Switch> <Route path="/" exact component={()=>(<h1>首頁</h1>)}></Route> <Route path="/form" exact component={FormCom}></Route> <Route path="/login" exact component={()=>(<h1>登陸頁</h1>)}></Route> <Route path="/logininfo" exact component={LoginInfo}></Route> <Route path="/admin" exact component={()=>(<h1>admin頁,登陸成功</h1>)}></Route> <Route path="/abc" exact component={()=>(<h1>abc1頁,登陸成功</h1>)}></Route> <Route path="/abc" exact component={()=>(<h1>abc2頁,登陸成功</h1>)}></Route> </Switch> </Router> </div> ) } }
解決React數據管理(狀態管理),用於中大型,數據比較龐大,組件之間數據交互多的狀況下使用。若是你不知道是否須要使用Redux,那麼你就不須要用它!
* 解決組件的數據通訊。
* 解決數據和交互較多的應用
Redux只是一種狀態管理的解決方案!
Store:數據倉庫,保存數據的地方。
State:state是1個對象,數據倉庫裏的全部數據都放到1個state裏。
Action:1個動做,觸發數據改變的方法。
Dispatch:將動做觸發成方法
Reducer:是1個函數,經過獲取動做,改變數據,生成1個新state。從而改變頁面
安裝
Cnpm install redux --save
初始化數據
//建立倉庫 const store = createStore(reducer) //用於經過動做,建立新的state //reduce有2個做用,1初始化數據,第二個就是經過獲取動做,改變數據 const reducer = function(state={num:0},action){ console.log(action) switch(action.type){ case "add": state.num++; break; case 'decrement': state.num--; break; default: break; } return {...state}//至關於對象的COPY }
獲取數據
let state = store.getState()
修改數據(經過動做修改數據)
//經過倉庫的方法dispatch進行修改數據 store.dispatch({type:"add",content:{id:1,msg:"helloworld"}})
修改視圖(監聽數據的變化,從新渲染內容)
store.subscribe(()=>{ ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) })
完整案例
import React from 'react'; import ReactDOM from 'react-dom'; import {createStore} from 'redux' //用於經過動做,建立新的state const reducer = function(state={num:0},action){ console.log(action) switch(action.type){ case "add": state.num++; break; case 'decrement': state.num--; break; default: break; } return {...state}//至關於對象的COPY } //建立倉庫 const store = createStore(reducer) console.log(store) function add(){ //經過倉庫的方法dispatch進行修改數據 store.dispatch({type:"add",content:{id:1,msg:"helloworld"}}) console.log(store.getState()) } function decrement(){ //經過倉庫的方法dispatch進行修改數據 store.dispatch({type:"decrement"}) console.log(store.getState()) } //函數式計數器 const Counter = function(props){ //console.log(store.getState()) let state = store.getState() return ( <div> <h1>計數數量:{state.num}</h1> <button onClick={add}>計數+1</button> <button onClick={decrement}>計數-1</button> </div> ) } ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) store.subscribe(()=>{ ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) })
安裝
cnpm install react-redux --save
概念:
Provider組件:自動的將store裏的state和組件進行關聯。
MapStatetoProps:這個函數用於將store的state映射到組件的裏props
mapdispatchToProps:將store中的dispatch映射到組件的props裏,實現了方法的共享。
Connect方法:將組件和數據(方法)進行鏈接
使用:
初始化數據,實例化store
function reducer(state={num:0},action){ switch(action.type){ case "add": state.num++; break; default: break; } return {...state} } const store = createStore(reducer)
數據的獲取,數據的修改
要state映射到到組件的props中,將修改數據的方法映射到組件的props中
完整案例
import React from 'react'; import ReactDOM from 'react-dom'; import {createStore} from 'redux'; import {connect, Provider} from 'react-redux' class Counter extends React.Component{ render(){ console.log(this.props) //計數,經過stroe的state傳給props,直接經過props就能夠將state的數據獲取 const value = this.props.value; //將修改數據的事件或者方法傳入到props const onAddClick = this.props.onAddClick; //等同於vuex的mapMutation mapState return ( <div> <h1>計數的數量:{value}</h1> <button onClick={onAddClick}>數字+1</button> <button onClick={this.props.onAddClick5}>數字+5</button> </div> ) } } let ActionFnObj={ add:function(state,action){ state.num++ return state }, addNum:function(state,action){ state.num = state.num + action.num; return state } } function reducer(state={num:0},action){ if(action.type.indexOf('redux')===-1){ state = ActionFnObj[action.type](state,action) return {...state} }else{ return state; } } const store = createStore(reducer) //將state映射到props函數 function mapStateToProps(state){ return { value:state.num } } const addAction = { type:'add' } //將修改state數據的方法,映射到props,默認會傳入store裏的dispach方法 function mapDispatchToProps(dispatch){ return { onAddClick:()=>{dispatch(addAction)}, onAddClick5:()=>{dispatch({type:"addNum",num:5})} } } //將上面的這2個方法,將數據倉庫的state和修改state的方法映射到組件上,造成新的組件。 const App = connect( mapStateToProps, mapDispatchToProps )(Counter) ReactDOM.render( <Provider store={store}> <App></App> </Provider>, document.querySelector("#root") )
npm install antd-mobile --save
按須要導入(自動導入用到的css樣式):
npm install babel-plugin-import --save
2.配置
npm run eject
3.Packjson文件
"babel": { "presets": [ "react-app" ], "plugins": [ ["import", { "libraryName": "antd-mobile", "style": "css" }] ] }
其他參考官網