安裝
npm i react react-dom
- react包是核心, 提供創(chuàng)建元素, 組件等功能。
- react-dom包提供DOM相關(guān)功能。
坑點(diǎn): 小伙伴再直接安裝時(shí)是不會(huì)生成node_modules, 需要 npm init -y進(jìn)行初始化生成package.json文件, 在進(jìn)行安裝就可以了
導(dǎo)入
- 引入react和react-dom的兩個(gè)文件
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
- 創(chuàng)建React元素
// 創(chuàng)建元素節(jié)點(diǎn)
// 1. 元素名稱
// 2. 元素屬性 傳對(duì)象
// 3. 元素內(nèi)容
let title = React.createElement('li', null, 'hellow react');
- 渲染到頁(yè)面
// 1.要渲染的元素
// 2.要渲染到那個(gè)元素里面
ReactDOM.render(title, document.querySelector('#root'));
安裝腳手架
- 初始化項(xiàng)目
npx create-react-app 項(xiàng)目名
- npx目的:提升包內(nèi)提供的命令行工具的使用體驗(yàn)
- 啟動(dòng)項(xiàng)目
npm start
JSX的使用
產(chǎn)生原因
由于通過(guò)createElement()方法創(chuàng)建的React元素有一些問(wèn)題, 代碼比較繁瑣,結(jié)構(gòu)不直觀,無(wú)法一眼看出描述的結(jié)構(gòu),不優(yōu)雅,用戶體驗(yàn)不好。
概述
JSX是JavaScript XML 的簡(jiǎn)寫(xiě),表示在JavaScript代碼中編寫(xiě)HTML格式的代碼
優(yōu)勢(shì):聲明式語(yǔ)法更加直觀, 與HTML結(jié)構(gòu)相同,降低了學(xué)習(xí)成本,提升開(kāi)發(fā)效率。
為什么在腳手架中可以使用JSX語(yǔ)法
- JSX 不是標(biāo)準(zhǔn)的ECMAScript語(yǔ)法,它是ECMAScript的語(yǔ)法拓展
- 需要使用babel編譯處理后,才能在瀏覽器環(huán)境中使用
- create-react-app腳手架中已經(jīng)默認(rèn)有該配置,無(wú)需手動(dòng)配置
- 編譯JSX語(yǔ)法的包: @bable/preset-react
注意點(diǎn)
- React元素的屬性名使用駝峰命名法
- 特殊屬性名:class -> className,for -> htmlFor,tabindex -> tabIndex
- 如果沒(méi)有子節(jié)點(diǎn)的React元素可以用
/>來(lái)結(jié)束 - 推薦:使用 小括號(hào)包裹JSX,從而避免JS中自動(dòng)插入分號(hào)報(bào)錯(cuò)
JSX語(yǔ)法
條件渲染
let isLoading = true
let loading = ()=>{
if(isLoading){
return <div>Loading...</div>
}
return <div>加載完成</div>
}
列表渲染
let arr = [{
id: 1,
name: '肖'
}, {
id: 2,
name: '小'
}, {
id: 3,
name: '笑'
}]
let arrMap = () => {
return (
<ul>
{arr.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
)
}
樣式處理
在style里面通過(guò)對(duì)象的方式傳遞數(shù)據(jù)
let arrMap = () => {
return (
<ul>
{arr.map(item => <li key={item.key} style={{ "color": "red", "backgroundColor": "pink" }}> {item.name} </li>)}
</ul>
)
}
不過(guò)這種方式比較麻煩,不方便閱讀,而且還會(huì)導(dǎo)致代碼比較繁瑣,權(quán)重性高
類(lèi)名-className
創(chuàng)建css文件編寫(xiě)樣式代碼
.container {
text-align: center
}
在js中進(jìn)行引入,然后設(shè)置類(lèi)名即可
import './css/index.css'
<li className='container' key={item.id} style={{'color': 'red',"backgroundColor": 'pink'}}>{item.name}</li>
React組件
- 組件是React的主要,使用React就是在用組件
- 組件表示頁(yè)面中的部分功能
- 組合多個(gè)組件實(shí)現(xiàn)完整的頁(yè)面功能
- 特點(diǎn):可復(fù)用、獨(dú)立、可組合
組件的創(chuàng)建方式
函數(shù)創(chuàng)建組件
- 函數(shù)組件:使用JS的函數(shù)創(chuàng)建組件
- 約定1:函數(shù)名稱必須以大寫(xiě)字母開(kāi)頭
- 約定2:函數(shù)組件必須有返回值,表示該組件的結(jié)構(gòu)
- 如果返回值為null,表示不渲染任何內(nèi)容
function Hello() {
return <div>這是第一個(gè)函數(shù)組件</div>
}
類(lèi)組件
- 使用ES6語(yǔ)法的class創(chuàng)建的組件
- 約定1:類(lèi)名稱也必須要大寫(xiě)字母開(kāi)頭
- 約定2:類(lèi)組件應(yīng)該繼承React.Component父類(lèi),從而可以使用父類(lèi)中提供的方法或者屬性
- 約定3:類(lèi)組件必須提供 render 方法
- 約定4:render方法中必須要有return返回值
class Hello extends React.Component {
render() {
return (
<div>這是第一個(gè)類(lèi)組件</div>
)
}
}
React的事件處理
- React事件綁定語(yǔ)法與DOM事件語(yǔ)法相似
- 語(yǔ)法:on+事件名稱=事件處理函數(shù),比如 onClick = function(){}
- 注意:React事件采用駝峰命名法
class Hello extends React.Component {
clickHandle(e) {
console.log('肖帥哥點(diǎn)我了');
}
render() {
return (
<div onClick={this.clickHandle}>這是第一個(gè)類(lèi)組件</div>
)
}
}
事件對(duì)象
- 可以通過(guò)事件處理函數(shù)的參數(shù)獲取到事件對(duì)象
- React中的事件對(duì)象叫做:合成事件
- 合成事件:兼容所有瀏覽器,無(wú)需擔(dān)心跨瀏覽器兼容問(wèn)題
- 除兼容所有瀏覽器外,它還擁有和瀏覽器原生事件相同的接口,包括
stopPropagation()和preventDefault() - 如果你想獲取到原生事件對(duì)象,可以通過(guò)
nativeEvent屬性來(lái)進(jìn)行獲取
class Hello extends React.Component {
clickHandle(e) {
console.log(e.nativeEvent);
}
render() {
return (
<div><button onClick={this.clickHandle}>這是第一個(gè)類(lèi)組件</button></div>
)
}
}
有狀態(tài)和無(wú)狀態(tài)組件
- 函數(shù)組件又叫做 無(wú)狀態(tài)組件,類(lèi)組件又叫做 有狀態(tài)組件
- 狀態(tài)(state) 即數(shù)據(jù)
- 函數(shù)組件沒(méi)有自己的狀態(tài),只負(fù)責(zé)數(shù)據(jù)展示
- 類(lèi)組件有自己的狀態(tài),負(fù)責(zé)更新UI,讓頁(yè)面動(dòng)起來(lái)
State和SetState
state基本使用
- 狀態(tài)(state)即數(shù)據(jù),是組件內(nèi)部的私有數(shù)據(jù),只能在組件內(nèi)部使用
- state的值是對(duì)象,表示一個(gè)組件中可以有多個(gè)數(shù)據(jù)
- 通過(guò)this.state來(lái)獲取狀態(tài)
export default class extends React.Component {
constructor(){
super()
// 第一種初始化方式
this.state = {
count : 0
}
}
// 第二種初始化方式
state = {
count:1
}
render(){
return (
<div>計(jì)數(shù)器 :{this.state.count}</div>
)
}
}
setState() 修改狀態(tài)
- 狀態(tài)是可變的
- 語(yǔ)法:this.setState({要修改的數(shù)據(jù)})
- 注意:不要直接修改state中的值,這是錯(cuò)誤的
- setState() 作用:1.修改 state 2.更新UI
抽取事件處理函數(shù)
-
當(dāng)我們把上面代碼的事件處理程序抽取出來(lái)后,會(huì)報(bào)錯(cuò),找不到this
image.png
原因
在ES6箭頭函數(shù)中知道,箭頭函數(shù)本身是沒(méi)有this的,它只會(huì)去向外一層去尋找。
在JSX中寫(xiě)的事件處理函數(shù)可以找到this,因?yàn)橥鈱邮莚ender方法,在render方法里面的this剛好指向的是當(dāng)前實(shí)例對(duì)象。
事件綁定this指向
箭頭函數(shù)
- 利用箭頭函數(shù)自身不綁定this的特點(diǎn)
class App extends Component {
state = {
count: 1
}
add() {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<div>計(jì)數(shù)器 :{this.state.count}</div>
<button onClick={() => this.add()}>+1</button>
</div>
)
}
}
利用bind方法
利用原型bind方法是可以更改函數(shù)里面this的指向的,所以我們可以在構(gòu)造中調(diào)用bind方法,然后把返回的值賦值給我們的函數(shù)即可
class App extends Component {
constructor() {
super()
this.state = {
count: 1
}
// 通過(guò)bind方法改變了當(dāng)前函數(shù)中this的指向
this.add = this.add.bind(this);
}
add() {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<div>計(jì)數(shù)器 :{this.state.count}</div>
<button onClick={this.add}>+1</button>
</div>
)
}
}
class的實(shí)例方法
- 利用箭頭函數(shù)形式的class實(shí)例方法
// 事件處理程序
add = () => {
console.log('事件處理程序中的this:', this)
this.setState({
count: this.state.count + 1
})
}
表單處理
受控組件
- HTML中的表單元素是可輸入的,也就是有自己的可變狀態(tài)
- 而React中可變狀態(tài)通常保存在state中,并且只能通過(guò)
setState()方法來(lái)修改 - React講state與表單元素值value綁定在一起,有state的值來(lái)控制表單元素的值
-
受控組件:值受到react控制的表單元素
image.png
class App extends Component {
state = {
txt: ''
}
txtChanget = (e) => {
this.setState({
txt: e.target.value
})
}
render() {
return (
<div>
<input type="text" value={this.state.txt} onChange={this.txtChanget} />
</div>
)
}
}
多表單元素優(yōu)化
- 問(wèn)題:每個(gè)表單元素都有一個(gè)單獨(dú)的事件處理函數(shù),這樣太繁瑣
- 優(yōu)化:使用一個(gè)事件處理程序同時(shí)處理多個(gè)表單元素
class App extends Component {
state = {
txt: '',
isChecked: ''
}
txtChanget = ({ target }) => {
let value = target.type == 'checkbox' ? target.checked : target.value;
this.setState({
[target.name]: value
})
}
render() {
console.log(this.state.txt, this.state.isChecked)
return (
<div>
<input type="text" value={this.state.txt} onChange={this.txtChanget} name="txt" />
<input type="checkbox" value={this.state.isChecked} name="isChecked" onChange={this.txtChanget} />
</div>
)
}
}
非受控組件
- 說(shuō)明:借助于ref,使用元素DOM方式獲取表單元素值
- ref的作用:獲取DOM或者組件
class App extends Component {
txtRef = React.createRef();
getTxt = () => {
console.log(this.txtRef.current.value)
}
render() {
return (
<div>
<input type="text" ref={this.txtRef} />
<button onClick={this.getTxt}></button>
</div>
)
}
}
React組件進(jìn)階
組件通訊
組件是獨(dú)立且封閉的單元,默認(rèn)情況下,只能使用組件自己的數(shù)據(jù)。在組件化過(guò)程中,我們將一個(gè)完整的功能拆分成多個(gè)組件,以更好的完成整個(gè)應(yīng)用的功能。而在這個(gè)過(guò)程中,多個(gè)組件之間不可避免的要共享某些數(shù)據(jù)。為了實(shí)現(xiàn)這些功能,就需要打破組件的獨(dú)立封閉性,讓其與外界溝通,這個(gè)過(guò)程就是組件通訊
組件的props
- 組件時(shí)封閉的,要接受外部數(shù)據(jù)應(yīng)該通過(guò)props來(lái)實(shí)現(xiàn)
- props的作用:接收傳遞給組件的數(shù)據(jù)
- 傳遞數(shù)據(jù):給組件標(biāo)簽添加屬性
<Hello name="肖"></Hello>
接收數(shù)據(jù):函數(shù)組件通過(guò) 參數(shù) props接收數(shù)據(jù),類(lèi)組件通過(guò) this.props接收數(shù)據(jù)
- 函數(shù)組件獲取
const Hello = (props) => {
return <div>{props.name}</div>
}
- 類(lèi)組件獲取
class Hello extends React.Component {
render() {
return (
<div>{this.props.name}</div>
)
}
}
特點(diǎn)
- 可以給組件傳遞任意類(lèi)型的數(shù)據(jù)
- props是只讀屬性,不能對(duì)值進(jìn)行修改
- 注意:使用類(lèi)組件時(shí),如果寫(xiě)了構(gòu)造函數(shù),應(yīng)該將props傳遞給super(),否則,無(wú)法在構(gòu)造函數(shù)中獲取到props,其他的地方是可以拿到的
class Hello extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>{this.props.name}</div>
)
}
}
組件通訊的三種方式
父組件傳遞數(shù)據(jù)給子組件
- 父組件提供要傳遞的state數(shù)據(jù)
- 給子組件標(biāo)簽添加屬性,值為state中的數(shù)據(jù)
- 子組件中通過(guò)props接收父組件中傳遞的數(shù)據(jù)
子組件傳遞數(shù)據(jù)給父組件
// 子組件
class Hello extends React.Component {
state = {
name: '肖'
}
goApp = () => {
this.props.getMsg(this.state.name);
}
render() {
return (
<div>
<button onClick={this.goApp}></button>
</div>
)
}
}
// 父組件
class App extends Component {
getChildMsg = (msg) => {
console.log(msg);
}
render() {
return (
<div>
<Hello getMsg={this.getChildMsg}></Hello>
</div>
)
}
}
兄弟組件傳遞
- 將共享狀態(tài)(數(shù)據(jù))提升到最近的公共父組件中,由公共父組件管理這個(gè)狀態(tài)
- 這個(gè)稱為狀態(tài)提升
- 公共父組件職責(zé):1. 提供共享狀態(tài) 2.提供操作共享狀態(tài)的方法
- 要通訊的子組件只需要通過(guò)props接收狀態(tài)或操作狀態(tài)的方法
// 兄弟組件
class Child1 extends React.Component {
render() {
return (
<h1>計(jì)數(shù)器:{this.props.count}</h1>
)
}
}
class Child2 extends React.Component {
child2Add = () => {
this.props.add(1)
}
render() {
return (
<button onClick={this.child2Add}>+1</button>
)
}
}
// 父組件
class App extends Component {
state = {
count: 0
}
add = (count) => {
this.setState({
count: this.state.count + count
})
}
render() {
return (
<div>
<Child1 count={this.state.count}></Child1>
<Child2 add={this.add}></Child2>
</div>
)
}
}
Context
如果出現(xiàn)層級(jí)比較多的情況下(例如:爺爺傳遞數(shù)據(jù)給孫子),我們會(huì)使用Context來(lái)進(jìn)行傳遞
作用: 跨組件傳遞數(shù)據(jù)
const { Provider, Consumer } = React.createContext();
class Child extends React.Component {
render() {
return (
<div>子組件
<Consumer>
{data => <span>{data}</span>}
</Consumer>
</div>
)
}
}
// 父組件
class App extends Component {
render() {
return (
<Provider value="pink">
<div>
<Child></Child>
</div>
</Provider>
)
}
}
props效驗(yàn)
- 對(duì)于組件來(lái)說(shuō),props是外來(lái)的,無(wú)法保證組件使用者傳入什么格式的數(shù)據(jù),簡(jiǎn)單來(lái)說(shuō)就是組件調(diào)用者可能不知道組件封裝著需要什么樣的數(shù)據(jù)
- 如果傳入的數(shù)據(jù)不對(duì),可能會(huì)導(dǎo)致報(bào)錯(cuò)
- 關(guān)鍵問(wèn)題:組件的使用者不知道需要傳遞什么樣的數(shù)據(jù)
- props校驗(yàn):允許在創(chuàng)建組件的時(shí)候,指定props的類(lèi)型、格式等
安裝
- 安裝包
prop-types - 導(dǎo)入prop-types 包
- 使用
組件名.propTypes={}來(lái)給組件的props添加校驗(yàn)規(guī)則 - 校驗(yàn)規(guī)則通過(guò)PropTypes對(duì)象來(lái)指定
npm install --save prop-types
import PropTypes from 'prop-types'
// 子組件
class Child extends React.Component {
render() {
return (
<div>
{this.props.name}
</div>
)
}
}
// 不要寫(xiě)在前面,因?yàn)樵诔跏蓟笆菦](méi)有Child這個(gè)組件的
Child.propTypes = {
name: PropTypes.string
}
//父組件
class App extends React.Component {
render() {
return (
<div>
<Child name="xin"></Child>
</div>
)
}
}
常規(guī)約束規(guī)則
- 創(chuàng)建的類(lèi)型:
array、bool、func、number、object、string - React元素類(lèi)型:
element - 必填項(xiàng):
isRequired - 特定結(jié)構(gòu)的對(duì)象:
shape({}) - 更多的約束規(guī)則
image.png
props的默認(rèn)值
import PropTypes from 'prop-types'
// 子組件
class Child extends React.Component {
render() {
return (
<div>
{this.props.name}
</div>
)
}
}
// 不要寫(xiě)在前面,因?yàn)樵诔跏蓟笆菦](méi)有Child這個(gè)組件的
Child.defaultProps = {
name: '哈哈'
}
//父組件
class App extends React.Component {
render() {
return (
<div>
<Child></Child>
</div>
)
}
}


