React 学习笔记
導
1. react- 用于構建用戶界面的javaScript 庫
- 發送請求獲取數據
- 處理數據(過濾、整理)
- 操作dom 呈現頁面
react 是一個將數據渲染微HTML視圖的開源 JavaScript庫
2. facebook開發,且開源
3. 原生JavaScript
????????原生javaScript操作DOM繁瑣、效率低(DOM-APL 操作 UI)。
????????使用javascript直接操作DOM,瀏覽器會進行大量的重繪重排。
????????原生JavaScript沒有組件化編碼方案,代碼復用率低。
4. react 特點
- 采用組件化模式、聲明式編碼,提高開發效率及組件復用率。?
- React Native 中可以使用 React語法進行移動端開發
- 使用虛擬DOM + 優秀的Diffing算法,盡量減少與真實DOM的交互
1、hello? react
? ? ? ? react 核心庫和react-dom的引入要放在前面? ?
<!DOCTYPE html> <html lang="en"><head><meta chartset="UTF-8"><title>hello_react</title></head><body><!-- 準備一個容器 --><div id="test"></div><!-- 引入react核心庫 --><script src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom,用于支持react操作DOM --><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel,用于將jsx轉為js --><script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script><script type="text/babel"> /* 此處一定為babel*/// 1. 創建虛擬DOMconst VDOM = <h1>Hello,React</h1> /* 不用寫引號,因為不是字符串,是jsx*/// 2. 渲染虛擬DOM到頁面ReactDOM.render(VDOM, document.getElementById('test'))</script></body> </html>2.? 創建虛擬DOM
? ? ? ? JSX創建虛擬DOM更方便,相當于語法糖
// 1. 創建虛擬DOMconst VDOM = (<h1 id="title"><span>Hello,React</span></h1>) /* 不用寫引號,因為不是字符串,是jsx*/? ? ? ? JS 創建虛擬DON
// 1. 創建虛擬DOM const VDOM = React.createElement('h1', {id: 'title'}, React.createElement('span',{}, 'hello, React'))3. 虛擬DOM和真實DOM
? ? ? ? 虛擬DOM:?
? ? ? ? ? ? ? ? 1、本質上是一個Object對象,一般對象
? ? ? ? ? ? ? ? 2、虛擬DOM比較 ”輕",真實DOM比較 “重”, 因為虛擬DOM是React內部在用,無需真實DOM這么多的屬性
? ? ? ? ? ? ? ? 3、虛擬DOM最終會被React轉化成真實DOM,呈現在頁面上。
4. jsx 語法規則
? ? ? ? --XML早期用于存儲和傳輸的數據
? ? ? ? -- JSON 也是用于存儲和傳輸的數據,js內置對象
? ? ? ? ? 1、定義虛擬DOM時,不要寫引號
? ? ? ? ? 2、標簽中混入JS表達式時要用 {}
? ? ? ? ? 3、樣式的類名指定不用 class,要用className.
? ? ? ? ? 4、內聯樣式,要用style = {{key: value}} 的形式去寫
? ? ? ? ? 5、只有一個跟標簽
? ? ? ? ? 6、標簽必須閉合
? ? ? ? ? 7、標簽首字母
? ? ? ? ? ? (1)若小寫字母開頭,則將該標簽轉為 html同名元素,若html中無該標簽,則報錯
? ? ? ? ? ? (2)若大寫字母開頭,react就去喧嚷對應的組件,若組件沒有定義,則報錯
<!DOCTYPE html> <html lang="en"><head><meta chartset="UTF-8"><title>4_JSX語法規則</title><style>.title {background: orange;}</style></head><body><!-- 準備一個容器 --><div id="test"></div><!-- 引入react核心庫 --><script src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom,用于支持react操作DOM --><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel,用于將jsx轉為js --><script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script><script type="text/babel"> /* 此處一定為babel*/// 1. 創建虛擬DOMconst VDOM = (<h1 id="title" className="title"><span style= {{color: 'white',fontSize: '20px'}}>Hello,React</span></h1>) /* 不用寫引號,因為不是字符串,是jsx*/// 2. 渲染虛擬DOM到頁面ReactDOM.render(VDOM, document.getElementById('test'))</script></body> </html>5.?函數式組件
<!DOCTYPE html> <html lang="en"><head><meta chartset="utf-8"><title>06_函數式組件</title></head><body><!-- 準備一個容器 --><div id="test"></div><!-- 引入react核心庫 --><script src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom,用于支持react操作DOM --><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel,用于將jsx轉為js --><script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script><script type="text/babel">//1、創建函數式組件function MyComponent() {console.log(this); // 此處的this 是undefined,因為babel編譯之后開啟了嚴格模式return <h2>函數定義的組件(適用于【簡單組件】定義)</h2>}// 2、渲染組件到頁面ReactDOM.render(<MyComponent/>, document.getElementById('test'))</script></body> </html>? ? ? ?* 執行了ReactDOM.render(<MyComponent/>...之后,發生了什么)
? ? ? ?* ?1、React解析組件標簽,找到了MyComponent組件
? ? ? ?* ?2、發現組件是使用函數定義的,隨后調用該函數,將返回的虛擬DOM轉為真實的DOM,隨后呈現在頁面上。
注:嚴格模式下,禁止 this 指向 window
官方例子:
function Welcome(props) {return <h1>Hello, {props.name}</h1>; }const root = ReactDOM.createRoot(document.getElementById('root')); const element = <Welcome name="Sara" />; root.render(element)這個例子中發生了什么:
6. 類的基本知識
????????1. 類中的構造器不是必須寫的,要對實例進行一些初始化的操作,如添加指定屬性時才寫
? ? ? ? 2. 如果A類繼承了B類,且A類型寫了構造器,那么A類構造器中的super是必須要調用的
? ? ? ? 3. 類中所定義的方法,都是放在了類的原型對象上,供實列使用
<!DOCTYPE html> <html lang="en"><head><meta chartset="utf-8"><title>07_類基本知識</title></head><body><script type="text/javascript">/*1. 類中的構造器不是必須寫的,要對實例進行一些初始化的操作,如添加指定屬性時才寫2. 如果A類繼承了B類,且A類型寫了構造器,那么A類構造器中的super是必須要調用的3. 類中所定義的方法,都是放在了類的原型對象上,供實列使用*/// 創建一個Person類class Person {// 構造器方法constructor(name, age) {// 構造器中的 this 是指 類的實例對象this.age = agethis.name = name}// 一般方法speak() {// speak 方法放在了 類的原型對象上,供實例使用console.log(`我叫${this.name}, 我的年齡是${this.age}`);}}// 創建一個 Student類,繼承于Person類class Student extends Person {constructor(name, age, grade) {super(name, age) // 父類this.grade = grade}// 重寫父類繼承過來的方法speak() {console.log(`我叫${this.name}, 我的年齡是${this.age}, 我在讀${this.grade}`);}// study 方法放在了 Student類的原型對象上,供實例使用study() {console.log(`我很努力的學習`);}}const s1 = new Student('xiao', 15, '高一')console.log(s1);s1.speak();// 創建一個Person的實例對象// const p1 = new Person('tom', 21)// const p2 = new Person('jerry', 22)// console.log(p1);// console.log(p2);// p1.speak()// p2.speak()// p1.speak.call({ a: 1, b: 2}); apply({}) 可以更改函數里面的 this 指向,傳什么就指向什么;</script></body> </html>? ? ? ? 4、?類中可以直接寫賦值語句, 如下的含義?會直接往Car實例對象添加一個屬性,名為 a, 值為 1
class Car {// 類中可以直接寫復制語句,// 會直接往Car實例對象添加一個屬性,名為 a, 值為 1a = 1 } const c1 = new Car() console.log(c1);7. 類式組件
<script type="text/babel">// 1、創建類式組件class MyComponent extends React.Component {// render 是放到類原型對象上的,供實例使用render() {// render 中的 this 是MyComponent實例對象console.log(this);return <h2>我是類式組件(適用于復雜組件的定義)</h2>}}// 2、渲染組件到頁面ReactDOM.render(<MyComponent/>, document.getElementById('test'))</script>?執行了ReactDOM.render(<MyComponent/>...之后,發生了什么)
? ? ? ?1、React解析組件標簽,找到了MyComponent組件
? ? ? ?2、發現組件是使用類定義的,隨后new 出來該類的實例,并通過該實例調用到原型上的render方法。
? ? ? ??3、將render 返回的虛擬DOM轉為真實DOM。隨后呈現在頁面上
? ? ? ?
8. 組件中的state
- ?state 的值是對象(key-value的組合)
- 組件中render方法中的this為組件實例對象
- 組件自定義函數中的this 為 undefined解決辦法:
- bind 方法
- 箭頭函數
- 狀態數據不能直接修改更新,必須要用內置APL---?setState
? ? ? ? (1)? 元素綁定事件
? ? ? ? 注意寫法:onClick = { this.demo },不是?onClick = { this.demo()?},? 是函數的回調,不是函數的執行。
render() {return <h2 onClick={ this.demo }>今天天氣很{this.state.isHot ? '炎熱' : '涼爽'}, {this.state.wind}</h2>}? ? ? ? (2)?this的指向問題
? ? ? ? ? ? ? ? bind 可以解決 1、生成新的 函數? 2、更改函數中的 this
? ? ? ? ??(3) 狀態(state) 必須通過setState進行更新,且更新事一種合并,不是替換
? ? ? ? ?(4)render 函數調用,頁面更行;?狀態更新多少次,render函數就會調用多少次
9. state 精簡
? ? ? ? 1.? 不再寫構造器
? ? ? ? 2.? 自定義方法-----要用 賦值語句的形式 + 箭頭函數
注:?箭頭函數沒有 this,它會直接找外層的 this
<script type="text/babel">// 1、創建類式組件class Weather extends React.Component {// 初始化狀態state = {isHot: true,wind: '微風'}render() {return <h2 onClick={ this.demo }>今天天氣很{this.state.isHot ? '炎熱' : '涼爽'}, {this.state.wind}</h2>}// 箭頭函數沒有 this,它會直接找外層的 this// 自定義方法 --- 要用 賦值語句的形式 + 箭頭函數demo = () => {const isHot = this.state.isHotthis.setState({isHot: !isHot})}}// 2、渲染組件ReactDOM.render(<Weather/>, document.getElementById('test')) </script>11. props
在類組件中 直接 this.props就可以拿到 組件傳進來的值對象了
ES6 中三點運算符,可以展開數組,但是不可以展開 Object
React 的組件的props傳值,可以只用三點運算符 展開 Object,僅限于 組件的props的傳值
props是只讀,不可以修改
構造器是否接受 props,是否 傳遞給super,取決于:是否希望在構造器中通過this訪問 props
?React內置了一些 方法 對 props傳入的屬性進行 檢查,15.5版本之后React.PropTypes?已移入另一個包中了
<!-- unpkg 引入prop-types --><script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>?propTypes 使用方式:
// react 15.6版本之后Person.propTypes = {name: PropTypes.string.isRequired, // name 必填· 字符串sex: PropTypes.string, // sex 字符串age: PropTypes.number, // age 數字speak: PropTypes.func, // speak 函數}設置默認值,defaultProps
// 指定默認標簽屬性值Person.defaultProps = {sex: 'man', // sex 默認值為 manage: 18,}12. props簡寫
? ? ? ? 把 props的限制都寫在類里面,static 關鍵字定義
<!DOCTYPE html> <html lang="en"><head><meta chartset="utf-8"><title>12_props的簡寫</title></head><body><!-- 準備一個容器 --><div id="test"></div><!-- 引入react核心庫 --><script src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom,用于支持react操作DOM --><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel,用于將jsx轉為js --><script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script><!-- 引入prop-types --><script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script><script type="text/babel">// 1、創建類式組件class Person extends React.Component {// 對標簽屬性進行類型、必要性的限制static propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,}// 指定默認標簽屬性值static defaultProps = {sex: 'man', // sex 默認值為 manage: 18,}// 初始化狀態state = {}render() {const {name, sex, age} = this.propsreturn (<ul><li>name: {name}</li> <li>sex: {sex}</li> <li>age: {age}</li> </ul>)}}const p = { name: 'tom', sex: 'man', age: 20}// 2、渲染組件ReactDOM.render(<Person {...p}/>, document.getElementById('test')) </script></body> </html>13. 函數組件使用
function Person(props) {const {name, sex, age} = propsreturn (<ul><li>name: {name}</li> <li>sex: {sex}</li> <li>age: {age}</li> </ul>)}Person.propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number,}// 指定默認標簽屬性值Person.defaultProps = {sex: 'man', // sex 默認值為 manage: 18,}const p = { name: 'tom', sex: 'man', age: 20}// 2、渲染組件ReactDOM.render(<Person {...p}/>, document.getElementById('test'))14.? 字符串形式的 ref
? ? ? ? 官方不建議使用,以后會棄用
注意是 ref ,不是 refs
<script type="text/babel">// 1、創建組件class Demo extends React.Component{showMsg = () => {console.log(this.refs.input1.value);}showMsg2 = () => {console.log(this.refs.input2.value);}render() {return (<div><input ref="input1" type="text" placeholder="請輸入"/> <button onClick={this.showMsg}>點擊</button> <input ref="input2" onBlur={ this.showMsg2} type="text" placeholder="請輸入"/></div>)}}ReactDOM.render(<Demo/>, document.getElementById('test'))15. 回調形式的 ref
<script type="text/babel">// 1、創建組件class Demo extends React.Component{showMsg = () => {console.log(this.input1.value);}showMsg2 = () => {console.log(this.input2.value);}render() {return (<div><input ref={c => this.input1 = c} type="text" placeholder="請輸入"/> <button onClick={this.showMsg}>點擊</button> <input ref={c=> this.input2 = c} onBlur={ this.showMsg2} type="text" placeholder="請輸入"/></div>)}}ReactDOM.render(<Demo/>, document.getElementById('test'))16. React.createRef()?
?官方最推薦的寫法,createRef是只能存一個值,后面的值會直接覆蓋前面定義的值,鍵值對的形式存儲
input1 = React.createRef()
獲取值: this.input1.current.value
<script type="text/babel">// 1、創建組件class Demo extends React.Component{input1 = React.createRef()input2 = React.createRef()showMsg = () => {console.log(this.input1.current.value);}showMsg2 = () => {console.log(this.input2.current.value);}render() {return (<div><input ref={this.input1} type="text" placeholder="請輸入"/> <button ref="button1" onClick={this.showMsg}>點擊</button> <input ref={this.input2} onBlur={ this.showMsg2} type="text" placeholder="請輸入"/></div>)}}ReactDOM.render(<Demo/>, document.getElementById('test'))</script>17. 事件處理
18. 非受控組件
非受控組件相對于 受控組件,屬性沒有在 state狀態里面維護的都是 非受控組件,現造現取
<script type="text/babel">// 創建組件class Login extends React.Component{hundleSubmit = (event) => {event.preventDefault() // 阻止表單提交const {username, password} = thisalert(`用戶名:${username.value}, 密碼:${password.value}`)}render() {return (<form action="http://www.atguigu.com" onSubmit={ this.hundleSubmit}>用戶名:<input ref={c=>this.username = c} type="text" name="username"/>密碼:<input ref={c=>this.password = c} type="password" name="password"/><button>登錄</button></form>)}}ReactDOM.render(<Login/>, document.getElementById('test'))19. 受控組件
? ? ? ? 受控組件,數據都放在 state狀態里面維護,相當于 vue的數據雙向綁定?
<script type="text/babel">// 創建組件class Login extends React.Component{// 初始狀態state = {username: '',password: '',}saveUsername = (event) => {this.setState({username: event.target.value})}savePassword = (event) => {this.setState({password: event.target.value})}hundleSubmit = (event) => {event.preventDefault() // 阻止表單提交const {username, password} = this.statealert(`用戶名:${username}, 密碼:${password}`)}render() {return (<form action="http://www.baidu.com" onSubmit={ this.hundleSubmit}>用戶名:<input onChange={this.saveUsername} type="text" name="username"/>密碼:<input onChange={this.savePassword} type="password" name="password"/><button>登錄</button></form>)}}ReactDOM.render(<Login/>, document.getElementById('test'))20. 高階函數
?疑問:??this.setState({[data]: event.target.value}) 中的 [data]怎么就可以讀變量了呢
在數組里面是 array[a] = 223 就可以賦值數據, 同理?
21. 生命周期(舊)
? 1. 初始化階段:由ReactDOM.render() 觸發 -----初次渲染
? ? ? ? 1. constructor()
? ? ? ? 2. componentWillMount()
? ? ? ? 3. render()
? ? ? ? 4. componentDidMount()? ?------------ 常用,
????????????????一般在這做一些初始化的事,例如:開啟定時器、發送網絡請求、訂閱消息
2. 更新階段:由組件內部this.setState() 或父組件render觸發
? ? ? ? 1. shouldComponentUpdate()
? ? ? ? 2. componentWillUpdate()
? ? ? ? 3. render()? ? ?------------------- 必須使用的
? ? ? ? 4. componentDidUpdate()
3. 卸載組件:ReactDOM.unmountComponentAtNode()觸發
? ? ? ? 1. componentWillUnmount()? ----------- 常用
? ? ? ? ? ? ? ? 一般在這做一些收尾的事,例如:關閉定時器、取消訂閱消息
componentWillReceiveProps 這個鉤子是 父組件改變的時候,子組件會調這個勾子,
注意:初次渲染是不會調這個勾子的?
22. 生命周期(新)
?新的生命周期 對于 舊的生命周期 ,廢棄(即將廢棄)了 三個 生命鉤子: ;新提出了兩個生命鉤子:getDerivedStateFromProps、getSnapshotBeforeUpdate
1. 初始化階段: 由ReactDOM.render()觸發 ---------------初次渲染
? ? ? ? 1. constructor()
? ? ? ? 2. getDerivedStateFromProps
? ? ? ? 3. render()
? ? ? ? 4. componentDidMount()?------------ 常用,
????????????????一般在這做一些初始化的事,例如:開啟定時器、發送網絡請求、訂閱消息
2. 更新階段: 由組件內部this.setState()或父組件重新render觸發
? ? ? ? 1. getDerivedStateFromProps
? ? ? ? 2. shouldComponentUpdate()
? ? ? ? 3. render()
? ? ? ? 4. getSnapshotBeforeUpdate()
? ? ? ? 5. componentDidUpdate()
3. 卸載組件:由ReactDOM.unmountComponentAtNode()觸發
? ? ? ? 1. componentWilUnmount() ----------- 常用
? ? ? ? ? ? ? ? 一般在這做一些收尾的事,例如:關閉定時器、取消訂閱消息
????????
重要的鉤子
? ? ? ? 1. render: 初始化渲染或更新渲染調用
? ? ? ? 2. componentDidMount: 開啟監聽,發送ajax請求
? ? ? ? 3. componentWilUnmount: 做一些收尾工作,如:清理定時器
即將廢棄的鉤子
? ? ? ? 1. componentWillMount
? ? ? ? 2. componentWillReceiveProps
? ? ? ? 3. componentWillUpdate
23. DOM的 diffing算法
? ? ? ? 逐層對比,最小粒度是 標簽
經典面試題
1). react/vue 中key有什么作用?(key的內部原理是什么?)
2). 為什么遍歷列表是,key最好不要用index?
1. 虛擬DOM中key的作用??
? ? ? ? 1) 簡單的說:key是虛擬DOM對象的標識,在更新顯示時key起到及其重要的作用
? ? ? ? 2)詳細說:當狀態中的數據發生變化時,react會根據 【新數據】生成 【新的虛擬DOM】,隨后React進行【新虛擬DOM】與【舊虛擬DOM】的diff比較,比較規則如下:
? ? ? ? ? ? ? ? a. 舊虛擬DOM中找到了與新虛擬DOM相同的key
? ? ? ? ? ? ? ? ? 1. 若虛擬DOM中內容沒有變,直接使用之前的真實DOM
? ? ? ? ? ? ? ? ? 2. 若虛擬DOM中內容變了,則生成新的真實DOM,隨后替換掉頁面中之前的真實DOM
? ? ? ? ? ? ? ? b. 舊虛擬DOM中未找到與新虛擬DOM相同的key
? ? ? ? ? ? ? ? ? 根據數據創建新的真實的DOM,隨后渲染到頁面
2. 用index作為key可能會引發的問題:
? ? ? ? 1. 若對數據進行:逆序添加、逆序刪除等破環順序操作:會產生沒有必要的真實DOM更新 =》界面效果沒有問題,單效率低
? ? ? ? 2. 如果結構中還包含輸入類的DOM:會產生錯誤DOM更新 =》界面有問題
? ? ? ? 3. 注意:如果不存在對數據的逆序添加、逆序刪除等破環順序操作,僅用于渲染列表用于展示,使用index作為key是沒有問題的。
3. 開發中如何選擇key?
? ? ? ? 1. 最好使用每條數據的唯一標識作為key,比如:id、手機號、身份證號、學號等唯一值
? ? ? ? 2. 如果確定只是簡單的展示數據,用index也是可以的。
24. 手腳架創建react項目
? ? ?基于webpack 手腳架搭建
1、 react 提供用于創建react項目的腳手架:create-react-app
2、項目的整體技術架構:react+webpack+es6_eslint
3、使用腳手架開發的項目:模塊化、組件化、工程化
創建項目并啟動
1、全局安裝:npm install -g create-react-app
2、切換目錄,使用:create-react-app react_demo2
3、進入項目文件夾:cd react_demo2
4、啟動項目:npm start
目錄
? ? ??
25. 功能界面的組件化編碼流程
SPA (單頁面應用)
1. 拆分組件:拆分界面,抽取組件
2. 實現靜態組件:使用組件實現靜態頁面效果
3. 實現動態組件:
? ? ? ? a. 動態顯示初始化數據
? ? ? ? ? ? ? ? 數據類型
? ? ? ? ? ? ? ? 數據名稱
? ? ? ? ? ? ? ? 保存在哪個組件
? ? ? ? b. 交互(從綁定事件監聽開始)
* state 放在哪個組件:
? ? ? ? ----某個組件組件使用: 放在其自身的state中
? ? ? ? ---某些組件使用:放在他們共同的父組件state中,(狀態提升)
* 父子組件通信
? ? ? ? 1. 父組件 給 子組件傳遞數據: 通過props傳遞
? ? ? ? 2. 子組件 給父組件傳遞數據:通過 props傳遞,要求 父 提前給 子 傳一個函數
* 注意 defaultChecked 和 checked 的區別,類似 defaultValue 和 value 也是
* 狀態在哪里,操作狀態的方法就在哪里
26. react項目開發,vscode 好用的插件
?
持續學習更新中....
總結
以上是生活随笔為你收集整理的React 学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu 16.04 安装monac
- 下一篇: 提问的智慧(学习笔记)