一、react項目
前端react后端node:https://github.com/GainLoss/react-juejin
前端react后端Pyton:https://github.com/GainLoss/python-react
二、react理解
1.react優點
組件、單向數據、虛擬DOM、生態系統、JSX
組件:一個組件就像一個接受道具作為輸入並輸出聲明的函數接口。 UI應該由盡可能多的組件組成可以最大限度地提高可重用性。
單項數據:React使用單向數據流,因此只會更改數據結果更改UI。如果您使用Redux,則可以在全局應用程序中更改數據存儲,組件監聽那里的變化。
具體流程:(1)操作通過將數據傳輸到Dispatcher來啟動數據流。(2)Dispatcher接收操作並將數據傳遞到所有store。(3)store包含應用程序的狀態,並在收到相關操作后對其進行更新。(4)視圖從store接收數據並重新呈現組件。
虛擬DOM:虛擬DOM允許UI在UI變化中具有高效性。這個組件應呈現的內部和之間的過程實際渲染是什么,它允許React在不同的工作平台。
生態系統:react有豐富的生態,有很多插件可以供開發者使用。
2.react和vue的對比
相同之處:(1)使用虛擬DOM (2)組件化
不同之處:(1)react如果狀態變化,是從根節點開始重新渲染;vue是確定到某一個節點需要變化,只是更新這個節點;(2)react是用jsx渲染模板;vue使用的是Template模板渲染,還是Html模板;
選取:react生態比較好,插件多;vue學習難度低;
三、在創建項目的時候,各種坑和總結
關於react-router的坑和總結:
1.react-router現在版本是4,所以如果將嵌套的路由都放一塊的話,就會出錯:
報這種錯誤Warning: You should not use <Route component> and <Route children> in the same route;
所以將需要嵌套的路由放到你的組件中
2.在頁面有導航的時候,我們需要實現點擊導航跳轉頁面的功能,這時候我們需要在導航的render中這樣寫:
我們用Link: <li key={index}><Link to="/+{item.name}">{item.name}</Link></li> 而且我們需要引入一個import { Link } from 'react-router-dom'
3.我們想要獲取當前頁面的路由或者說是瀏覽器中地址欄的地址:
在當前組件中props里面有當前的地址,找一個恰當的生命周期鈎子然后再這個函數中this.props里面就可以獲取到,或者可以直接在render中return中元素里的{}里面直接獲取
4.react-router路由有兩種形式:
HashRouter這種的帶hash #
BrowerBouter這種是利用html5中history的,這種是需要服務器端支持的,兼容性不是很好
6.有時候需要實現,根據當前地址實現對應導航顯示:
在當前組件中獲取this.props,然后將這個值賦給this.state,在需要當前組件中渲染導航組件的位置,在導航組件中寫<Nav urlLocation={this.state.url}/>,最后在導航組件中獲取到this.props里面包含的就是當前路由地址
7.有時候我們需要實現點擊排序,給當前路由添加參數:我用的是Link這種方法
組件里面:
<div style={homeMainLeftTwodiv2}> { this.state.HomeMenutwo.map((item,index)=> <span key={index} className={this.query===item.sort?"homesortactive":''}> <Link to={{pathname:"/home",search: 'sort='+item.sort,}}>{item.name}</Link> <Route path="/home/:id" component={Home}/> </span> ) } </div>
在router路由中:還是和之前一樣的
8.想只是改變地址欄的地址而不是調轉頁面,就比如我當前頁面有兩個選擇,點擊選擇,改變地址欄地址,但是還是當前的組件
import createHashHistory from 'history/createHashHistory' const history = createHashHistory() //點擊一級菜單事件 clickTop(event) { let that = this; let tab = event.currentTarget.dataset.tab; that.setState({ menuOne: tab }) console.log(that.setState) history.push({ pathname: '/home/'+tab, }) } { this.state.HomeMenuTop.map((item, index) => <span key={index} className={this.state.menuOne === item.tab ? "homesortactive" : ""} data-tab={item.tab} onClick={this.clickTop}> {item.name}{this.state.menuOne} </span> ) }
9.react-router2遷移到react-router4的特性:https://github.com/gmfe/Think/issues/6
10.在npm start之后頁面出現這種錯誤Uncaught TypeError: Super expression must either be null or a function, not undefined
原因是:在編寫組件的時候React.Component寫錯了
11.在react中使用事件:
如果沒有用bind的話那么點擊事件只在頁面一開始的時候執行,不會在元素點擊的時候執行,只有用this.click.bind(this)就可以,在點擊元素的時候也執行這個函數
class FLeft extends React.Component{ constructor(props){ super(props) this.state={ currentIndex:0, } } clickTab(index,e){ this.setState({currentIndex:index}); } render(){ var styles={ width:'100%', height:'300px' } var index=this.state.currentIndex; return ( <div className="f_left"> <textarea className="f_left_text"></textarea> <div className='f_left_text_choose'> <span>圖片</span> <span>鏈接</span> <span>話題</span> <button>發布</button> </div> <div className='choose_tab'> <span onClick={this.clickTab.bind(this,0)} className={this.state.currentIndex===0?'active':''}>推薦</span> <span onClick={this.clickTab.bind(this,1)} className={this.state.currentIndex===1?'active':''}>動態</span> </div> </div> ) } }
12.在react中使用iconfont (Unicode編碼)
一般使用的時候直接用<i className="iconfont">編碼</i>這樣就可以了,但是當你循環出來i標簽的時候,那么iconfont使用的是字符串表示unicode編碼,那么我們需要改寫一下編碼
想使用字符串來傳遞的話,只要將 "" 改為 “\ue655” 即可。
13.在react中循環中設置點擊事件
這個里面只有把點擊事件設置成異步的才不會循環出全部的元素的點擊事件
1 <HomeHeader> 2 { 3 this.props.homeheader.map((item)=>{ 4 var id=item.id; 5 return <HomeHeaderItem onClick={()=>this.props.clickChangeList(id)} key={item.id}><Link to={{pathname:'/home/'+id}}>{item.val}</Link></HomeHeaderItem> 6 }) 7 } 8 </HomeHeader>
14.配置文件的路徑:
有時候在一個組件中要引入一個新的組件,可能路徑需要寫很多的../,現在我們需要設置一個單詞表示父級文件夾
背景:"react": "^16.5.2","react-dom": "^16.5.2","react-scripts": "2.0.4"
打開node_modules中的react-script中webpack.config.dev.js這個文件(是開發環境配置),里面的
resolve:{ alias: { 'react-native': 'react-native-web', '@': paths.appSrc //對應的是相同文件夾下面的paths.js文件夾里面 }, }
設置完成之后,在組件中引入import Header from '@/common/header/header.js'
關於在react中引入css或者引入外部文件:
1.在react中怎么引入css文件呢:
{ test:/\.css$/, exclude: /node_modules/, loader: "style-loader!css-loader" }
2.html元素中添加css樣式的時候:
兩種:一種是class名字填寫,但是在jsx中class需要寫成className; 二種是在行間寫樣式style={{}}里面放置樣式 ;三種是style={colorstyle}里面放置一個變量
關於react中元素渲染和數據交互的總結:
this.state.HomeMenuone.map((item,index)=>
<span key={index}>{item.name}</span>
)
如果不加的話,會出這種錯誤
2.在react中引入圖片的話,當然之前的直接放在src中也是可以的,但是比較好的方法是:
import img from './right.png' <img src={img}/>
這種方法有可能會出現這種錯誤:出現Uncaught Error: Module parse failed: Unexpected character '�' (1:0),這種我的解決辦法是重新npm install就可以了
3.在前后台交互的時候我用的是fetch實現的:
注意的是在fetch成功調取之后將結構賦給一個數組的時候,在then中需要用這個才能設置好this.setState({result:data}),然后map這個result
4.使用fetch獲取后台數據:
fetch("/list/show").then((response)=>{ if(response&&response.status===200){ return response.json(); } }).then((data)=>{ this.setState({result:data}) });
5.上面的是直接獲取后台的數據,但是有時候我們需要用fetch給后台傳參數(后台用的是express):
我們如果用get就是和上面是一樣的,但是如果我們用post是有區別的和之前的寫法,有兩種寫法:
一種:
if(this.props.location.search){ let idValue=this.props.location.search.split('=')[1]; fetch('/list/detail',{method:'POST',headers: { 'Content-Type': 'application/x-www-form-urlencoded' },body: `id=${idValue}`}).then((response)=>{ return response.json() }).then((result)=>{ this.setState({result:result}) }) }
二種:
if(this.props.location.search){ let idValue=this.props.location.search.split('=')[1]; let formData = new FormData(); formData.append("id",123); fetch('/list/detail',{method:'POST',body: formData}).then((response)=>{ return response.json() }).then((result)=>{ this.setState({result:result}) }) }
上面這兩種都可以;
另外后台因為用的是express,所以你需要在dev-server.js中添加一個body-parser這個模塊是為了解析客戶端請求的body的內容,內部使用JSON編碼,url編碼處理以及對文件的上傳處理。
關於react中事件處理的總結:
1.當我們想點擊元素,相應的改變state的時候,可以這樣:
//constructor this.clickMenu=this.clickMenu.bind(this) //點擊事件 clickMenu(event){ var that=this; let sort=event.currentTarget.dataset.sort; that.setState({query:sort}) } // render中 <div style={homeMainLeftTwodiv1}> { this.state.HomeMenuone.map((item,index)=> <span key={index} className={this.state.query===item.sort?"homesortactive":'' } data-sort={item.sort} onClick={this.clickMenu}> <Link to={ {pathname:"/home", search: 'sort='+item.sort,} } >{item.name}</Link> <Route path="/home/:id" component={Home}/> </span> ) } </div>