React
安裝
- 全局安裝腳手架
create-react-app
npm i -g create-react-app
- 創建項目
create-react-app projectName
- 打開項目
cd projectName
- 啓動項目
npm start
- 項目默認的配置項是隱藏的,通過執行以下命令可以暴露配置項
npm run eject
文件結構
React和ReactDom
React負責邏輯控制,數據 -> VDOM,創建虛擬DOM
react中的的JSX語法
JSX => React.createElement(…)
ReactDom渲染實際DOM,VDOM -> DOM 。
ReactDOM.render(
<div>react</div>,
document.getElementById('root')
);
JSX
JSX是⼀種JavaScript的語法擴展,其格式⽐較像模版語⾔,但事
實上完全是在JavaScript內部實現的。
使用JSX
1、表達式{}
的使用
const name = 'react';
const jsx = <h1>{name}</h1>
2、函數
function sayHi(name){
return `${name} says hi`;
}
const jsx = <h1>{sayHi('react')}</h1>
3、條件語句
const name = 'react';
const show = true
const content = show ? <h1>{name}</h1> : null
const jsx = <h1>{content}</h1>
4、數組
const arr = [1,2,3,4].map(val =><li key={val}>{val}</li>)
const jsx=(
<div>
<ul>{arr}</ul>
</div>
)
5、屬性
靜態值用雙引號,動態值則是一個花括號。
import logo from './logo.svg'
const jsx = (
<div>
<img src={logo} style={{width:50}} />
</div>
)
組件
組件是抽象的獨⽴功能模塊,react應⽤程序由組件構建⽽成。
組件有兩種形式
function組件 和 class組件
1、 class組件
class組件通常擁有狀態和⽣命週期,繼承了 Component,實現render⽅法。
創建一個組件
import React,{ Component } from 'react'
export default class Com1 extends Component{
render(){
const content = '這是一個組件'
return (
<div>
{content}
</div>
)
}
}
在需要使用該組件是時候直接引入即可。
import Com1 from '@/components/com1'
2、 function組件
函數組件通常⽆狀態,僅關注內容展示,返回渲染結果即可。
function com2(){
return(
<div>
這是function組件
</div>
)
}
從React16.8開始引⼊了hooks,函數組件也能夠擁有狀態。
組件狀態管理
如果組件中數據會變化,並影響⻚⾯內容,則組件需要擁有狀態(state)並維護狀態。
class組件中的狀態管理
class組件使⽤state和setState維護狀態
創建一個組件
import React,{ Component } from 'react'
export default class Com1 extends Component{
constructor(props){
super(props); // 繼承Component
this.state={
name : '組件1'
}
// 使⽤state屬性維護狀態,在構造函數中初始化狀態
}
render(){
return (
<div>
{this.state.name}
</div>
)
}
}
state中的狀態不能直接更改
this.state.name = '這就是組件1啊' // 錯誤
而是要採用setState()
this.setState({
name:'這就是組件1啊'
})
而setState()
方法是異步的,也就說你在該函數裏面改變某個值後,立即調用該屬性,其值並未發生改變。
this.setState({
name:'這就是組件1啊'
})
console.log(this.state.name) // 組件1
如果想在改變後立即調用,有以下三種方式:
- 傳遞函數給setState方法
this.setState({
name:'這是組件1啊'
},()=>{
console.log(this.state.name) // 這是組件1啊
})
import React,{ Component } from 'react'
export default class Com1 extends Component{
constructor(props){
super(props);
this.state={
counter: 0
}
}
componentDidMount(){
this.setState({
counter:this.state.counter+3
})
this.setState({
counter:this.state.counter+1
}) // 調用了兩次,其實只執行了最後一個+1
}
render(){
return (
<div>
{this.state.counter} // {/* 1 */}
</div>
)
}
}
this.setState((nextState,props)=>({
counter:nextState.counter+1
}))
this.setState((nextState,props)=>({
counter:nextState.counter+1
}))
// 此時執行counter 爲 2
- 使用定時器
其實就是利用了事件隊列。
componentDidMount() {
setTimeout(() => {
this.changeValue();
console.log(this.state.name); // 這就是組件1啊
}, 0);
}
changeValue = () => {
this.setState({
name: '這就是組件1啊' // 初始值是 組件1
})
}
- 原生事件中修改
componentDidMount() {
document.body.addEventListener('click',this.changeValue,false)
}
changeValue = () => {
this.setState({
name: '這就是組件1啊'
})
}
總結: setState只有在合成事件和⽣命週期函數中是異步的,在原⽣事件如addEventListener和setTimeout、setInterval中都是同步的。
原⽣事件綁定不會通過合成事件的⽅式處理,⾃然也不會進⼊更新事務的處理流程。setTimeout也⼀樣,在setTimeout回調執⾏時已經完成了原更新組件流程,也不會再進⼊異步更新流程,其結果⾃然就是是同步的了。
function組件中的狀態管理
函數組件通過hooks api維護狀態
import React,{ useState,useEffect } from 'react'
export default function Com2(){
const [name,setName] = useState('組件2')
useEffect(()=>{
setTimeout(()=>{
setName('這是組件2了')
})
})
return (
<div>{name}</div>
)
}
其實可以把useEffect()
看作是class組件中的componentDidMount()
、componentDidUpdate()
以及componentWillUnmount()
三者的組合。
事件處理
事件回調函數注意綁定this指向,常⻅三種⽅法:
- 構造函數中綁定並覆蓋:this.change =this.change.bind(this)
- ⽅法定義爲箭頭函數:change = ()=>{},使⽤箭頭函數,不需要指定回調函數this,且便於傳遞參數
- 事件中定義爲箭頭函數:onChange={()=>this.change()}
react⾥遵循單項數據流,沒有雙向綁定,輸⼊框要設置value
和onChange,稱爲受控組件
組件通信
props傳遞
屬性:
// 父
<Son name="leo"></Son>
// son.js
<h1>{this.props.name}</h1>
函數
// 父
<Son change={this.onChange}></Son>
// son.js
this.props.change(this.state.name) // 可以把子組件的信息傳入父組件,這個叫做狀態提升。
生命週期
v16.4之後的生命週期中廢棄了以下三個方法:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
如果要使用的話需要在頭部加上UNSAFE_
;
同時引入了兩個新的生命週期函數:
- static getDerivedStateFromProps
- getSnapshotBeforeUpdate
廢棄緣由:
原來(React v16.0前)的⽣命週期在React v16推出的Fiber之後
就不合適了,因爲如果要開啓async rendering,在render函數
之前的所有函數,都有可能被執⾏多次。
原來(React v16.0前)的⽣命週期有哪些是在render前執⾏的呢?
- componentWillMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
static getDerivedStateFromProps(props,state)
getDerivedStateFromProps 會在調⽤ render ⽅法之前調⽤,並且在初始掛載及後續更新時都會被調⽤。它應返回⼀個對象來更新 state,如果返回 null 則不更新任何內容。
請注意,不管原因是什麼,都會在每次渲染前觸發此⽅法。與UNSAFE_componentWillReceiveProps 形成對⽐,後者僅在⽗組件重新渲染時觸發,⽽不是在內部調⽤ setState 時。
static getDerivedStateFromProps(props, state) 在組件創建時和更新時的render⽅法之前調⽤,它應該返回⼀個對象來更新狀態,或者返回null來不更新任何內容。
import React, { Component } from 'react'
export default class Com1 extends Component {
constructor(props) {
super(props);
this.state = {
name: '組件1',
}
}
static getDerivedStateFromProps(props,state){
const {name} = state
return name !== '組件11'?null:{name:'如果輸入結果等於組件11就返回這個state'}
}
change(e){
this.setState({
name:e.target.value
})
}
render() {
return (
<div>
{this.state.name} {/* 1 */}
<input onChange={(e)=>this.change(e)} value={this.state.name}/>
</div>
)
}
}
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近⼀次渲染輸出(提交到DOM 節點)之前調⽤。它使得組件能在發⽣更改之前從 DOM中捕獲⼀些信息(例如,滾動位置)。此⽣命週期的任何返回值將作爲參數傳遞給 componentDidUpdate()。就相當於獲取了上一次渲染的state的值。
此⽤法並不常⻅,但它可能出現在 UI 處理中,如需要以特殊⽅
式處理滾動位置的聊天線程等。
import React, { Component } from 'react'
export default class Com1 extends Component {
constructor(props) {
super(props);
this.state = {
name: '組件1',
}
}
getSnapshotBeforeUpdate(prevProps,prevState){
const {name} = prevState
console.log('get Snapshot: ',name) // 輸出組件1
return null
}
componentDidUpdate(){ // 假如第一次更新name的值爲‘組件11’
console.log('componentDidUpdate: ',this.state.name) // 輸出組件11
}
change(e){
this.setState({
name:e.target.value
})
}
render() {
return (
<div>
{this.state.name} {/* 1 */}
<input onChange={(e)=>this.change(e)} value={this.state.name}/>
</div>
)
}
}