1、Hello,Word
React干嘛的,有什么用可以去官網(wǎng)瞧瞧。
安裝
react核心庫(kù)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
react操作dom的庫(kù)
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
babel轉(zhuǎn)義jsx語(yǔ)法
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
提供根節(jié)點(diǎn)
<div id="app"></div>
編寫JSX
babel語(yǔ)法
<script type="text/babel">
//創(chuàng)建虛擬dom
const VDOM = <h1>Hello,Word</h1>
ReactDOM.render(VDOM,document.getElementById('app'))
</script>

2、JSX的語(yǔ)法規(guī)則
2-1、虛擬dom是什么類型的?
const VDOM = <h1>Hello,Word</h1>
console.log(VDOM instanceof Object)
console.log(VDOM)

其實(shí)JSX中虛擬
dom就是個(gè)json對(duì)象,當(dāng)然原生的dom節(jié)點(diǎn)其實(shí)也是對(duì)象
image.png
只不過(guò)相對(duì)于原生來(lái)說(shuō)少了很多屬性。
2-2、虛擬DOM使用變量
var hId = 't-h1';
var Txt = '變量文本';
var style = {color:'white',backgroundColor:'orange'}
const VDOM = (
<h1 id={hId} style={style}>{Txt}</h1>
)
ReactDOM.render(VDOM,document.getElementById('app'))

注意:1、在虛擬dom中定義類名需要使用
className
2、使用內(nèi)聯(lián)樣式需要使用花括號(hào)把對(duì)象包裹起來(lái)
3、定義虛擬DOM不需要使用單引號(hào),如果使用就會(huì)變成字符串了
4、虛擬DOM只能有一個(gè)根節(jié)點(diǎn)
5、虛擬DOM的節(jié)點(diǎn)定義規(guī)則:
5-1、首字母小寫,如果為html中的同名標(biāo)簽,則渲染為同名元素,如果不是則直接渲染改標(biāo)簽,且會(huì)報(bào)錯(cuò)
5-2、首字母大寫,則為React中的自定義組件
3、React組件
3-1、函數(shù)式組件
//注意這里需要大寫首字母原因請(qǐng)看jsx語(yǔ)法規(guī)則
const data = ['Angulay', 'React', 'Vue'];
function Demo(abc) {
console.log(this)
return (
<div>
<h1>自定義組件</h1>
<ul>
{data.map(item => <li key={item}>{item}</li>)}
</ul>
</div>
)
}
ReactDOM.render(<Demo />, document.getElementById('app'))
注意此處的函數(shù)中
this并不是window,也不是React實(shí)例,因?yàn)樵赽abel中轉(zhuǎn)義會(huì)添加嚴(yán)格模式use strict嚴(yán)格模式下,禁止函數(shù)內(nèi)this指向window
3-2、類式組件
class HelloMessage extends React.Component{
render(){
return <h1>類式組件的定義</h1>
}
}
ReactDOM.render(<HelloMessage />,document.getElementById('app'))
類式組件定義規(guī)則:1、必須繼承自
React.Component這個(gè)類
2、必須含有一個(gè)render方法,且必須有一個(gè)返回值
3、類中可以不用constructor方法
當(dāng)ReactDOM.render一個(gè)類組件發(fā)生了什么?
1、
React解析組件標(biāo)簽,找到了自定義組件。
2、發(fā)現(xiàn)自定義組件是類定義,隨后new出一個(gè)實(shí)例出來(lái),并且調(diào)用原形上render方法
3、講原形上render返回的虛擬dom返回在真是dom上
4、狀態(tài) State
我們先看下類式組件的
this到底有些什么東西?
class MyWeatch extends React.Component {
render() {
console.log(this);
return (
<div className="test">
Hello,Word
</div>
)
}
}
ReactDOM.render(<MyWeatch />, document.getElementById('app'))

state已被掛在在組件的實(shí)例對(duì)象上
4-1、案例使用state進(jìn)行操作
class MyWeacth extends React.Component{
constructor(props){
super(props)
this.state = {
isHot:false
}
}
render(){
const {isHot} = this.state;
return <h1>今天天氣很{isHot?'炎熱':'涼爽'}</h1>
}
}
注意:你必須使用構(gòu)造器
constructor,并且需要接受
4-2、使用事件處理調(diào)用函數(shù)
class Weatch extends React.Component{
constructor(props){
super(props)
this.state = {
isHot:false
}
}
render(){
const {isHot} = this.state;
return <h1 onClick={this.handleHot.bind(this)}>今天天氣很{isHot?'炎熱':'涼爽'}</h1>
}
handleHot(){
console.log(this.state.isHot)
}
}
注意:1、在React中監(jiān)聽事件我們使用原生的方法在標(biāo)簽上寫入方法,并且是駝峰命名
2、如果你直接賦值原型函數(shù),則該函數(shù)的this為undefined,所以必須是使用bind處理this指向
4-3、改變State的值
根據(jù)上述例子我們會(huì)發(fā)現(xiàn)直接更改state.isHot的值,雖然他的值確實(shí)被改變了,但是最終視圖并沒有被改變!
、、、
handleHot(){
console.log(this.state.isHot) 你會(huì)發(fā)現(xiàn)值確實(shí)被改變了
this.state.isHot = !this.state.isHot
}
在React中你不可以直接改變狀態(tài)的值,你必須使用父類原型中的
setState方法進(jìn)行改變數(shù)據(jù)。
handleStatus() {
this.setState({
isHot: !this.state.isHot
})
}
已經(jīng)實(shí)現(xiàn)了功能,視圖也更新了
4-4、疑問(wèn),setState是替換了state的整個(gè)對(duì)象,還是對(duì)象中的具體屬性?
class HelloMessage extends React.Component {
constructor(props) {
super(props)
this.state = {
isHot: false,
isTxt: '測(cè)試文字'
}
}
render() {
const { isHot, isTxt } = this.state
return <h1 onClick={this.handleStatus.bind(this)}>測(cè)試啊{isHot ? '可以' : 'no no'},案例:{isTxt}</h1>
}
handleStatus() {
this.setState({
isHot: !this.state.isHot
})
console.log(this.state)
}
}

會(huì)發(fā)現(xiàn)
setState只是改變了具體的某個(gè)屬性,并沒有對(duì)整個(gè)state的值進(jìn)行賦值,它的操作類似于Object.assign(this.state,arguments)
4-5、疑問(wèn)?對(duì)state進(jìn)行更新,構(gòu)造器constructor、render、依賴的事件函數(shù)他們會(huì)被調(diào)用么?調(diào)用多少次?
用代碼說(shuō)話
class HelloMessage extends React.Component {
constructor(props) {
console.log('constructor');
super(props)
this.state = {
isHot: false,
isTxt: '測(cè)試文字'
}
}
render() {
console.log('render');
const { isHot, isTxt } = this.state
return <h1 onClick={this.handleStatus.bind(this)}>測(cè)試啊{isHot ? '可以' : 'no no'},案例:{isTxt}</h1>
}
handleStatus() {
console.log('handleStatus');
this.setState({
isHot: !this.state.isHot
})
}
}
我們點(diǎn)擊h1標(biāo)簽看看怎么打印的?
image.png
通過(guò)這次小案例 我們就知道了:
1、構(gòu)造器constructor只會(huì)在自定義組件第一次綁定的時(shí)候才會(huì)調(diào)用一次,除非你在多個(gè)地方使用了該自定義組件
2、render函數(shù)會(huì)在調(diào)用setState/props改變,父組件更新,時(shí)會(huì)調(diào)用
3、事件處理函數(shù)當(dāng)然只會(huì)在你每次觸發(fā)的時(shí)候在調(diào)用。
4-6、精簡(jiǎn)寫法
首先我們先復(fù)習(xí)下普通的類的寫法
class Person{
name="人";
age = 18;
constructor(){
this.eye = 2;
}
handle = ()=>{
console.log(this)
}
handleProto(){
}
}
請(qǐng)問(wèn)下?
name、age、handle函數(shù)他們被放在哪了?
image.png
他們被放在了實(shí)例的自身屬性上??!不是原型上,所以React的精簡(jiǎn)寫法來(lái)了!
class HelloMessage extends React.Component {
state = { isHot: false, }
render() {
const { isHot } = this.state
return <h1 onClick={this.handleStatus}>測(cè)試啊{isHot?'1':'2'}</h1>
}
handleStatus = () => {
this.setState({
isHot: !this.state.isHot
})
}
}
5、Prop傳值
想象一個(gè)場(chǎng)景,如果我們自己封裝了一個(gè)自定義組件,但是組件里面的用到的數(shù)據(jù)有些是需要用戶傳進(jìn)來(lái)的,但是不可能讓用戶自己修改里面的代碼吧?所以我們引入一個(gè)概念
Props
class HelloMessage extends React.Component {
render() {
const { name, age } = this.props;
return <h1>姓名:{name},年齡:{age}</h1>
}
}
ReactDOM.render(<HelloMessage name="tom" age="18" />, document.getElementById('app'))
5-1、更簡(jiǎn)便的傳值
利用展開運(yùn)算符
...進(jìn)行解構(gòu)對(duì)象,我們知道大部分的數(shù)據(jù)我們都是后臺(tái)傳過(guò)來(lái)的,所以我們可以在外部定義一個(gè)json對(duì)象模擬數(shù)據(jù)
class HelloMessage extends React.Component {
render() {
const { name, age } = this.props;
return <h1>姓名:{name},年齡:{age}</h1>
}
}
let p = { name: 'tom', age: 18 }
ReactDOM.render(<HelloMessage {...p} />, document.getElementById('app'))
5-2、Props的規(guī)則驗(yàn)證
例如上述案例,我們可以知道,這用戶傳值隨心所欲,如我不傳姓名,或者姓名我傳數(shù)字怎么辦?所以我們需要限制他的傳值類型
image.png
在老版本上React對(duì)象上掛載了一個(gè)PropTypes對(duì)象,不過(guò)現(xiàn)在已被移除了,移到一個(gè)單獨(dú)的包中
我們引入csdn單獨(dú)的PropTypes的包
<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
我們看下PropTypes身上到底有些什么東西
console.log(PropTypes)

5-2-1、PropTypes的使用規(guī)則
你需要在自定義組件的類名添加一個(gè)
靜態(tài)屬性propTypes注意是小寫的p
class MyComponent extends React.Component{
static propTypes = {
name:PropType.string,
age:PropType.number
}
}
這是基本的驗(yàn)證規(guī)則
props屬性必傳isRequired
static propTypes = {
name:PropType.string.isRequired, //必傳
age:PropType.number
}
props之屬性默認(rèn)值
你需要給自定義組件添加靜態(tài)的defaultProps屬性
static defaultProps = {
name:'Tom'
}
props是只讀的,單向數(shù)據(jù)流
5-3、如果使用構(gòu)造器constructor,那么我不接收pops,會(huì)怎么樣
官方案例
、、、
{
constructor(props){
super(props)
console.log(this.props)
}
}
//不接收props
{
constructor(){
super()
console.log(this.props)//undefined
}
}
如果你需要在構(gòu)造器
constructor中操作props那么你就需要把props傳給分類
6、Refs
獲取原生dom對(duì)象,和vue中的用法是一致的,在虛擬節(jié)點(diǎn)上添加
ref屬性
6-1、字符串設(shè)置refs 即將廢棄
為什么會(huì)被廢棄?過(guò)時(shí) API:String 類型的 Refs
handleClick = ()=>{
console.log(this.refs)
}
render(){
return <h1 ref="ish" onClick={this.handleClick}>Refs使用</h1>
}
6-2、回調(diào)形式refs
也就是在 ref賦值的時(shí)候?qū)懭胍粋€(gè)函數(shù)
6-2-1、內(nèi)聯(lián)回調(diào)函數(shù)
render(){
return <h1 ref={curr=>this.ish = curr}>Refs的使用</h1>
}
但是注意的是:
1、內(nèi)聯(lián)回調(diào)函數(shù)不會(huì)往refs對(duì)象中添加屬性,在這里你相當(dāng)于在實(shí)例身上添加了一個(gè)ish的屬性
2、內(nèi)聯(lián)回調(diào)形式的refs會(huì)在組件更新狀態(tài)的時(shí)候調(diào)用兩次,一次的參數(shù)值為null第二次才是真正的節(jié)點(diǎn)
6-2-2、賦值一個(gè)函數(shù)的形式
saveH = (curr)=>{
this.ish = curr
}
render(){
return <h1 ref={this.saveH}>Refs的使用</h1>
}
這個(gè)可以避免內(nèi)聯(lián)回調(diào)的兩個(gè)缺點(diǎn),但是,他又會(huì)增加組件實(shí)例上的屬性過(guò)多且很雜。所以一般我們還是采用內(nèi)聯(lián)形式的方式
6-3、使用最新的API createRef
$refs = React.createRef()
handleClick = ()=>{
console.log(this.$refs);
}
render() {
return <div ref={this.$refs} onClick={this.handleClick}>
側(cè)是是是
</div>
}
遺憾是使用
createRef創(chuàng)建出來(lái)的屬性 只能是"專人專用",也就是說(shuō)如果還有第二個(gè)節(jié)點(diǎn)需要使用ref那么又得重新使用createRef創(chuàng)建一個(gè)新的屬性出來(lái)
7、高階函數(shù)/函數(shù)柯里化
什么是高階函數(shù)?
1、如果一個(gè)函數(shù)的參數(shù)是一個(gè)函數(shù)那么該函數(shù)就是高階函數(shù)
2、如果一個(gè)函數(shù)返回了一個(gè)函數(shù),那么該函數(shù)也是高階函數(shù)
閉包、Promise、setTimeOut、Array.map、、、等等
7-1、在React中使用高階函數(shù)
想象一個(gè)場(chǎng)景,如果一個(gè)虛擬dom綁定的事件做的事都幾乎一樣,那么我們沒必要定義多個(gè)函數(shù),排除內(nèi)聯(lián)函數(shù)(箭頭函數(shù))
handleClick = (type)=>{
****
console.log(type)
switch(type){、、、}
}
render(){
return (
<div>
<span onClick={this.handleClick('type1')}>測(cè)試1</span>
<span onClick={this.handleClick('type2')}>測(cè)試2</span>
<span onClick={this.handleClick('type3')}>測(cè)試3</span>
</div>
)
}
如果我們直接直接這樣,就相當(dāng)于在render的時(shí)候React自己幫我們調(diào)用了這個(gè)函數(shù),后面就不會(huì)響應(yīng)我們的點(diǎn)擊事件,解決辦法,返回一個(gè)函數(shù)
handleClick = (type)=>{
return (event)=>{
}
}
render(){
return (
<div>
<span onClick={this.handleClick('type1')}>測(cè)試1</span>
<span onClick={this.handleClick('type2')}>測(cè)試2</span>
<span onClick={this.handleClick('type3')}>測(cè)試3</span>
</div>
)
}
7-2、函數(shù)柯里化
含義:通過(guò)函數(shù)調(diào)用繼續(xù)返回的函數(shù)的方式,實(shí)現(xiàn)多次接收參數(shù)最后統(tǒng)一處理的函數(shù)編碼方式
不用柯里化求三個(gè)值得和
function sum(a,b,c){return a+b+c}
柯里化
function sum(a){
return (b)=>{
return (c)=>{
return a+b+c
}
}
}
8、React生命周期(舊)

1、組件掛載前=>
componentWillMount
2、組件掛載后=>componentDidMount
3、組件卸載前=>componentWillUnmount
4、組件更新前=>componentWillUpdate
5、組件更新后=>componentDidUpdate
6、組件更新閥門=>shouldComponentUpdate
7、父組件render后并改變了子組件props監(jiān)聽第二次變化=>componentWillReceiveProps
知識(shí)點(diǎn):
- 主動(dòng)卸載一個(gè)組件ReactDOM.unmountComponentAtNode(節(jié)點(diǎn))
- 在生命周期中你會(huì)發(fā)現(xiàn)帶有Will都是觸發(fā)前,帶有Did都是觸發(fā)完成后
8-1 最新生命周期

我們知道react是要經(jīng)歷三個(gè)階段掛載、更新、卸載
掛載:
constructor(初始化)
getDerivedStateFromProps
render
componentDidMount
更新:
getDerivedStateFromProps
shouldComponentUpdate
getSnapshotBeforeUpdate
componentDidUpdate
卸載
componentWillUnMount
9、React腳手架
10、React路由
React的路由:react-router(比較綜合可以給react native使用)、react-router-dom(web端)



