react
他是一個(gè)用于構(gòu)建用戶界面的 JavaScript 庫(kù)
React-安裝
- 安裝 nodeJS
- 安裝create-react-app
npm install -g create-react-app
創(chuàng)建項(xiàng)目
create-react-app myreact
// myreact 項(xiàng)目名稱
啟動(dòng)項(xiàng)目
cd myreact
yarn start
// npm run start
默認(rèn)項(xiàng)目地址:http://localhost:3000/
React文件結(jié)構(gòu)和JSX語(yǔ)法
第一個(gè)react項(xiàng)目
打開 src/App.js 刪除默認(rèn)代碼 得到 hello react
import React, { Component } from 'react';
//導(dǎo)入React和 React.Component
class App extends Component {
// App根組件繼承 React.compoent
render() {
// 渲染 并返回一段html結(jié)構(gòu)
return (
<div className="App">
<h1>你好react</h1>
</div>
);
}
}
export default App;
//導(dǎo)出默認(rèn) App根組件
JSX語(yǔ)法
JSX 是一個(gè)看起來(lái)很像 html 的 JavaScript 語(yǔ)法擴(kuò)展。
js和html混合
1. 只能有一個(gè)根節(jié)點(diǎn)
return (
<div className="App">
<h1>你好react</h1>
</div>
);
// Classname="App" 就是根節(jié)點(diǎn)
2. 可以執(zhí)行javascript表達(dá)式 {}
{1+1}
{i == 1 ? '對(duì)的!' : '錯(cuò)誤的'}
3. 類名class 變成 className
<div className="App">
</div>
4. 行內(nèi)樣式 展開
var myStyle = {
"font-size": "14px",
"color": "#FF0000"
}
return (
<div className="App">
<h1 style={myStyle}>你好react</h1>
</div>
);
5. 注釋 {/* 注釋 */}
6. 數(shù)組里面可以直接寫html節(jié)點(diǎn)
var arr = [
<h1>組件渲染</h1>,
<h1>虛擬dom</h1>
]
return (
<div className="App">
{arr}
</div>
);
組件
可以這么說(shuō),一個(gè) React 應(yīng)用就是構(gòu)建在 React 組件之上的。
創(chuàng)建組件 Child.js
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子組件</h1>
<hr/>
</div>
);
}
}
調(diào)用組件
01. 導(dǎo)入組件
import Child from './components/Child.js'
02 使用組件
return (
<div className="App">
<Child/>
<h1>App根組件</h1>
</div>
);
完成代碼
import React, { Component } from 'react';
import Child from './components/Child.js'
// 導(dǎo)入組件
class App extends Component {
render() {
return (
<div className="App">
<Child/>
<h1>App根組件</h1>
</div>
);
}
}
export default App;
//導(dǎo)出默認(rèn) App根組件
React State(狀態(tài))
state 是組件的當(dāng)前狀態(tài),可以把組件簡(jiǎn)單看成一個(gè)“狀態(tài)機(jī)”,根據(jù)狀態(tài) state 呈現(xiàn)不同的 UI 展示。 一旦狀態(tài)(數(shù)據(jù))更改,組件就會(huì)自動(dòng)調(diào)用 render 重新渲染 UI,這個(gè)更改的動(dòng)作會(huì)通過(guò) this.setState 方法來(lái)觸發(fā)。
初始化組件 state
添加一個(gè)類構(gòu)造函數(shù)來(lái)初始化狀態(tài) this.state
constructor() {
super(); //調(diào)用父對(duì)象構(gòu)造函數(shù)
this.state={name:"dandan",age:18}
}
使用state
return (
<div className="App">
大家好我是{this.state.name}今年{this.state.age}歲了
</div>
);
完整代碼
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state={name:"dandan",age:18}
}
render() {
return (
<div className="App">
大家好我是{this.state.name}今年{this.state.age}歲了
</div>
);
}
}
export default App;
React Props
state 和 props 主要的區(qū)別在于 props 是不可變的,而 state 可以根據(jù)與用戶交互來(lái)改變。這就是為什么有些容器組件需要定義 state 來(lái)更新和修改數(shù)據(jù)。 而子組件只能通過(guò) props 來(lái)傳遞數(shù)據(jù)。
傳遞prop給子組件
return (
<div className="App">
<Child name="dandan"/>
<Child name="段鵬"/>
<Child />
</div>
);
子組件使用props
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
render() {
return (
<div className="App">
<Child name="dandan"> </Child>
<Child name="段鵬"></Child>
<Child ></Child>
</div>
);
}
}
export default App;
完整代碼
App.js
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
render() {
return (
<div className="App">
<Child name="dandan"> </Child>
<Child name="段鵬"></Child>
<Child ></Child>
</div>
);
}
}
export default App;
Child.js
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子組件 我的名字是{this.props.name}</h1>
<hr/>
</div>
);
}
}
Child.defaultProps = {
name:"保密"
}
// props 默認(rèn)值
事件處理
React 元素的事件處理和 DOM 元素類似
React 事件綁定屬性的命名采用駝峰式寫法,而不是小寫。
如果采用 JSX 的語(yǔ)法你需要傳入一個(gè)函數(shù)作為事件處理函數(shù),而不是一個(gè)字符串(DOM 元素的寫法)
javascript寫法
<button onclick="showMsg()">
按鈕
</button>
react寫法
<button onClick={showMsg}">
按鈕
</button>
完整react代碼
import React, { Component } from 'react';
class App extends Component {
showMsg(){
alert("來(lái)自react問(wèn)候!");
}
render() {
return (
<div className="App">
<button onClick={this.showMsg}>按鈕</button>
</div>
);
}
}
export default App;
setState 改變r(jià)eact狀態(tài)
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {num:1}
}
addNum(){
this.setState({num:this.state.num+1})
}
render() {
return (
{this.state.num}
{this.addNum()}}>按鈕
);
}
}
export default App;
用箭頭函數(shù)是為了保證函數(shù)里面this的正確指向br 你也可以用bind方法
按鈕
React 表單雙向綁定
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {num:1}
}
changeNum(e){
this.setState({num:e.target.value})
}
render() {
return (
<div className="App">
<input type="text" value={this.state.num} onChange={this.changeNum.bind(this)}/>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default App;
動(dòng)態(tài)的添加更改class
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {bg:'red'}
}
changeClass(e){
this.setState(pre=>{
return ({bg:pre.bg==='red'?'blue':'red'});
})
}
render() {
return (
<div className="App">
<button className={this.state.bg} onClick={this.changeClass.bind(this)}>按鈕</button>
</div>
);
}
}
export default App;
添加style
render() {
var css = {
borderRadius:"6px",
padding:"8px 16px",
color:'#fff',
background:'blue'
}
return (
<div className="App">
<button style={css}>按鈕</button>
</div>
);
}
}
React 條件渲染
條件性地渲染一塊內(nèi)容
三目運(yùn)算符號(hào)
render() {
var isLogin = true;
return (
<div className="App">
{isLogin?'歡迎您回來(lái)主人':'請(qǐng)登陸'}
</div>
);
}
& &運(yùn)算符
在 JavaScript 中,true && expression 總是返回 expression,而 false && expression 總是返回 false。
因此,如果條件是 true,&& 右側(cè)的元素就會(huì)被渲染,如果是 false,React 會(huì)忽略并跳過(guò)它。
render() {
var isLogin = false;
return (
<div className="App">
{isLogin &&'歡迎您回來(lái)主人'}
</div>
);
}
列表渲染
我們可以使用 JavaScript 的 map() 方法來(lái)創(chuàng)建列表。
初始化列表數(shù)據(jù)
constructor(props) {
super(props);
this.state={
list:[{name:'vue'},{name:'react'},{name:'angular'}]
}
}
map渲染列表
return (
<div className="App">
{this.state.list.map(
(item,index)=>{
return (
<div key={index}>{item.name}</div>
)
}
)}
</div>
);
完整代碼
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state={
list:[{name:'vue'},{name:'react'},{name:'angular'}]
}
}
render() {
return (
<div className="App">
{this.state.list.map(
(item,index)=>{
return (
<div key={index}>{item.name}</div>
)
}
)}
</div>
);
}
}
export default App;
Key 可以在 DOM 中的某些元素被增加或刪除的時(shí)候幫助 React 識(shí)別哪些元素發(fā)生了變化。因此你應(yīng)當(dāng)給數(shù)組中的每一個(gè)元素賦予一個(gè)確定的標(biāo)識(shí)。
一個(gè)元素的 key 最好是這個(gè)元素在列表中擁有的一個(gè)獨(dú)一無(wú)二的字符串。通常,我們使用來(lái)自數(shù)據(jù)的 id 作為元素的 key:
元素沒有確定的 id 時(shí),你可以使用他的序列號(hào)索引 index 作為 key:
組件生命周期
組件的生命周期可分成三個(gè)狀態(tài):
Mounting:已插入真實(shí) DOM
Updating:正在被重新渲染
Unmounting:已移出真實(shí) DOM
componentWillMount
在渲染前調(diào)用,在客戶端也在服務(wù)端。一般用的比較少,更多的是用在服務(wù)端渲染
1、組件剛經(jīng)歷constructor,初始完數(shù)據(jù)
2、組件還未進(jìn)入render,組件還未渲染完成,dom還未渲染
componentDidMount
在第一次渲染后調(diào)用,只在客戶端。之后組件已經(jīng)生成了對(duì)應(yīng)的DOM結(jié)構(gòu),可以通過(guò)this.getDOMNode()來(lái)進(jìn)行訪問(wèn)。 如果你想和其他JavaScript框架一起使用,可以在這個(gè)方法中調(diào)用setTimeout, setInterval或者發(fā)送AJAX請(qǐng)求等操作(防止異步操作阻塞UI)。
組件第一次渲染完成,此時(shí)dom節(jié)點(diǎn)已經(jīng)生成,可以在這里調(diào)用ajax請(qǐng)求,返回?cái)?shù)據(jù)setState后組件會(huì)重新渲染
componentWillReceiveProps
在組件接收到一個(gè)新的 prop (更新后)時(shí)被調(diào)用。這個(gè)方法在初始化render時(shí)不會(huì)被調(diào)用。
shouldComponentUpdate
返回一個(gè)布爾值。在組件接收到新的props或者state時(shí)被調(diào)用。在初始化時(shí)或者使用forceUpdate時(shí)不被調(diào)用。
可以在你確認(rèn)不需要更新組件時(shí)使用。
componentWillUpdate
在組件接收到新的props或者state但還沒有render時(shí)被調(diào)用。在初始化時(shí)不會(huì)被調(diào)用。
componentDidUpdate
在組件完成更新后立即調(diào)用。在初始化時(shí)不會(huì)被調(diào)用。
componentWillUnmount
在組件從 DOM 中移除之前立刻被調(diào)用。
class Demo extends Component {
constructor(props, context) {
//如果想(在組件其他地方是可以直接接收的)使用props或context,則需要以參數(shù)形式傳入。
//只要組件存在constructor,就必要要寫super,否則this指向會(huì)錯(cuò)誤
super(props, context);
this.state = {
data: 1
};
},
componentWillMount () {
// 在組件掛載之前調(diào)用,且全局只調(diào)用一次。如果在這個(gè)鉤子里可以setState,render后可以看到更新后的state,不會(huì)觸發(fā)重復(fù)渲染。
// 該生命周期可以發(fā)起異步請(qǐng)求,并setState。(React v16.3后廢棄該生命周期,可以在constructor中完成設(shè)置state)
// 不推薦在這里發(fā)起ajax請(qǐng)求,若返回?cái)?shù)據(jù)為空,則容易造成界面空白,影響渲染效果
},
componentDidMount () {
//組件第一次渲染完成,此時(shí)dom節(jié)點(diǎn)已經(jīng)生成,可以在這里調(diào)用ajax請(qǐng)求,返回?cái)?shù)據(jù)setState后組件會(huì)重新渲染
},
componentWillReceiveProps (nextProps) {
// 在接受父組件改變后的props需要重新渲染組件時(shí)用到的比較多
// 通過(guò)對(duì)比nextProps和this.props,將nextProps setState為當(dāng)前組件的state,從而重新渲染組件
nextProps.data !== this.props.data && this.setState({
data: nextProps.data
},() => {
console.log("new data...");
});
},
shouldComponentUpdate (nextProps, nextState) {
// react性能優(yōu)化非常重要的一環(huán)。
// 組件接受新的state或者props時(shí)調(diào)用,我們可以設(shè)置在此對(duì)比前后兩個(gè)props和state是否相同,
// 如果相同則返回false阻止更新,因?yàn)橄嗤膶傩誀顟B(tài)一定會(huì)生成相同的dom樹,
// 這樣就不需要?jiǎng)?chuàng)造新的dom樹和舊的dom樹進(jìn)行diff算法對(duì)比,節(jié)省大量性能,尤其是在dom結(jié)構(gòu)復(fù)雜的時(shí)候。
},
componentWillUpdate (nextProps, nextState) {
// 組件初始化時(shí)不調(diào)用,只有在組件發(fā)生更新需要重新渲染時(shí)才調(diào)用
},
componentDidUpdate (prevProps, prevState) {
// 組件初始化時(shí)不調(diào)用,組件更新渲染完成后調(diào)用,此時(shí)dom節(jié)點(diǎn)加載完成,可以獲取到dom節(jié)點(diǎn)。
// react只會(huì)在第一次初始化成功會(huì)進(jìn)入componentDidmount,
// 之后每次重新渲染后都會(huì)進(jìn)入這個(gè)生命周期,這里可以拿到prevProps和prevState,即更新前的props和state。
// 該鉤子內(nèi)setState有可能會(huì)觸發(fā)重復(fù)渲染,需要謹(jǐn)慎判斷,否則會(huì)進(jìn)入死循環(huán)
},
render () {
return (
<div>This is Demo!</div>
);
},
componentWillUnmount () {
// 組件將要卸載時(shí)調(diào)用,一些事件監(jiān)聽和定時(shí)器需要在此時(shí)清除。
},
componentDidCatch (error, info) {
//React 16 中引入,用來(lái) 捕獲組件的錯(cuò)誤。
//如果 render() 函數(shù)拋出錯(cuò)誤,則會(huì)觸發(fā)該函數(shù)。
//錯(cuò)誤在渲染階段中被捕獲,但在事件處理程序中不會(huì)被捕獲。
}
}
我們應(yīng)當(dāng)將AJAX 請(qǐng)求放到 componentDidMount 函數(shù)中執(zhí)行,主要原因有下:
React 可能會(huì)多次頻繁調(diào)用 componentWillMount,如果我們將 AJAX 請(qǐng)求放到 componentWillMount 函數(shù)中,那么顯而易見其會(huì)被觸發(fā)多次,自然也就不是好的選擇。
如果我們將 AJAX 請(qǐng)求放置在生命周期的其他函數(shù)中,我們并不能保證請(qǐng)求僅在組件掛載完畢后才會(huì)要求響應(yīng)。如果我們的數(shù)據(jù)請(qǐng)求在組件掛載之前就完成,并且調(diào)用了setState函數(shù)將數(shù)據(jù)添加到組件狀態(tài)中,對(duì)于未掛載的組件則會(huì)報(bào)錯(cuò)。而在 componentDidMount 函數(shù)中進(jìn)行 AJAX 請(qǐng)求則能有效避免這個(gè)問(wèn)題。
componentDidMount() {
this.getMovie();
}
getMovie(){
fetch("http://www.endata.com.cn/API/GetData.ashx",{
method:"post",
body:"MethodName=BoxOffice_GetPcHomeList",
headers:{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
})
.then(res=>res.json())
.then(res=>{
console.log(res)
})
}
子組件調(diào)用父組件方法|向父組件傳遞參數(shù)
父親傳一個(gè)函數(shù)props
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
showMsg(msg){
alert(msg);
}
render() {
return (
<div className="App">
<Child name="曾慶林" fun={this.showMsg}></Child>
</div>
);
}
}
export default App;
子組件在箭頭函數(shù)執(zhí)行props
import React,{Component} from 'react' export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子組件 我的名字是{this.props.name}</h1>
<button onClick={()=>{this.props.fun('我愛我的祖國(guó)')}}>調(diào)用父親函數(shù)方法</button>
<hr/>
</div>
);
}
}