摘要:背景介紹入門實例教程起源于的內部項目,因為該公司對市場上所有框架,都不滿意,就決定自己寫一套,用來架設的網站。做出來以后,發現這套東西很好用,就在年月開源了。也就是說,通過鉤子函
react - JSX React 背景介紹
React 入門實例教程
React 起源于 Facebook 的內部項目,因為該公司對市場上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設 Instagram 的網站。做出來以后,發現這套東西很好用,就在2013年5月開源了。
什么是React
A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
用來構建UI的 JavaScript庫
React 不是一個 MVC 框架,僅僅是視圖(V)層的庫
React 官網
React 中文文檔
特點1 使用 JSX語法 創建組件,實現組件化開發,為函數式的 UI 編程方式打開了大門
2 性能高的讓人稱贊:通過 diff算法 和 虛擬DOM 實現視圖的高效更新
3 HTML僅僅是個開始
> JSX --TO--> EveryThing - JSX --> HTML - JSX --> native ios或android中的組件(XML) - JSX --> VR - JSX --> 物聯網為什么要用React
1 使用組件化開發方式,符合現代Web開發的趨勢
2 技術成熟,社區完善,配件齊全,適用于大型Web項目(生態系統健全)
3 由Facebook專門的團隊維護,技術支持可靠
4 ReactNative - Learn once, write anywhere: Build mobile apps with React
5 使用方式簡單,性能非常高,支持服務端渲染
6 React非常火,從技術角度,可以滿足好奇心,提高技術水平;從職業角度,有利于求職和晉升,有利于參與潛力大的項目
React中的核心概念1 虛擬DOM(Virtual DOM)
2 Diff算法(虛擬DOM的加速器,提升React性能的法寶)
虛擬DOM(Vitural DOM)React將DOM抽象為虛擬DOM,虛擬DOM其實就是用一個對象來描述DOM,通過對比前后兩個對象的差異,最終只把變化的部分重新渲染,提高渲染的效率為什么用虛擬dom,當dom反生更改時需要遍歷 而原生dom可遍歷屬性多大231個 且大部分與渲染無關 更新頁面代價太大
如何實現一個 Virtual DOM 算法
理解 Virtual DOM
VituralDOM的處理方式1 用 JavaScript 對象結構表示 DOM 樹的結構,然后用這個樹構建一個真正的 DOM 樹,插到文檔當中
2 當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異
3 把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,視圖就更新了
Diff算法Reconciliation diff
diff算法 - 中文文檔
不可思議的 react diff
React diff 算法
當你使用React的時候,在某個時間點 render() 函數創建了一棵React元素樹,
在下一個state或者props更新的時候,render() 函數將創建一棵新的React元素樹,
React將對比這兩棵樹的不同之處,計算出如何高效的更新UI(只更新變化的地方)
React中有兩種假定:
1 兩個不同類型的元素會產生不同的樹(根元素不同結構樹一定不同)
2 開發者可以通過key屬性指定不同樹中沒有發生改變的子元素
Diff算法的說明 - 1如果兩棵樹的根元素類型不同,React會銷毀舊樹,創建新樹
// 舊樹Diff算法的說明 - 2// 新樹執行過程:destory Counter -> insert Counter
對于類型相同的React DOM 元素,React會對比兩者的屬性是否相同,只更新不同的屬性
當處理完這個DOM節點,React就會遞歸處理子節點。
// 舊 // 新 只更新:className 屬性 // 舊 // 新 只更新:color屬性Diff算法的說明 - 3
1 當在子節點的后面添加一個節點,這時候兩棵樹的轉化工作執行的很好
// 舊
2 但是如果你在開始位置插入一個元素,那么問題就來了:
// 舊
為了解決以上問題,React提供了一個 key 屬性。當子節點帶有key屬性,React會通過key來匹配原始樹和后來的樹。
// 舊
說明:key屬性在React內部使用,但不會傳遞給你的組件
推薦:在遍歷數據時,推薦在組件中使用 key 屬性:
注意:key只需要保持與他的兄弟節點唯一即可,不需要全局唯一
注意:盡可能的減少數組index作為key,數組中插入元素的等操作時,會使得效率底下
React的基本使用安裝:npm i -S react react-dom
react:react 是React庫的入口點
react-dom:提供了針對DOM的方法,比如:把創建的虛擬DOM,渲染到頁面上
// 1. 導入 react import React from "react" import ReactDOM from "react-dom" // 2. 創建 虛擬DOM // 參數1:元素名稱 參數2:元素屬性對象(null表示無) 參數3:當前元素的子元素string||createElement() 的返回值 const divVD = React.createElement("div", { title: "hello react" }, "Hello React!!!") // 3. 渲染 // 參數1:虛擬dom對象 參數2:dom對象表示渲染到哪個元素內 參數3:回調函數 ReactDOM.render(divVD, document.getElementById("app"))createElement()的問題
說明:createElement()方式,代碼編寫不友好,太復雜
var dv = React.createElement( "div", { className: "shopping-list" }, React.createElement( "h1", null, "Shopping List for " ), React.createElement( "ul", null, React.createElement( "li", null, "Instagram" ), React.createElement( "li", null, "WhatsApp" ) ) ) // 渲染 ReactDOM.render(dv, document.getElementById("app"))JSX 的基本使用
注意:JSX語法,最終會被編譯為 createElement() 方法
推薦:使用 JSX 的方式創建組件
JSX - JavaScript XML
安裝:npm i -D babel-preset-react (依賴與:babel-core/babel-loader)
注意:JSX的語法需要通過 babel-preset-react 編譯后,才能被解析執行
/* 1 在 .babelrc 開啟babel對 JSX 的轉換 */ { "presets": [ "env", "react" ] } /* 2 webpack.config.js */ module: [ rules: [ { test: /.js$/, use: "babel-loader", exclude: /node_modules/ }, ] ] /* 3 在 js 文件中 使用 JSX */ const dv = (JSX的注意點Hello JSX!) /* 4 渲染 JSX 到頁面中 */ ReactDOM.render(dv, document.getElementById("app"))
注意 1: 如果在 JSX 中給元素添加類, 需要使用 className 代替 class
類似:label 的 for屬性,使用htmlFor代替
注意 2:在 JSX 中可以直接使用 JS代碼,直接在 JSX 中通過 {} 中間寫 JS代碼即可
注意 3:在 JSX 中只能使用表達式,但是不能出現 語句!!!
注意 4:在 JSX 中注釋語法:{/* 中間是注釋的內容 */}
React組件React 組件可以讓你把UI分割為獨立、可復用的片段,并將每一片段視為相互獨立的部分。
組件是由一個個的HTML元素組成的
概念上來講, 組件就像JS中的函數。它們接受用戶輸入(props),并且返回一個React對象,用來描述展示在頁面中的內容
React創建組件的兩種方式1 通過 JS函數 創建(無狀態組件)
2 通過 class 創建(有狀態組件)
函數式組件 和 class 組件的使用場景說明: 1 如果一個組件僅僅是為了展示數據,那么此時就可以使用 函數組件 2 如果一個組件中有一定業務邏輯,需要操作數據,那么就需要使用 class 創建組件,因為,此時需要使用 stateJavaScript函數創建
注意:1 函數名稱必須為大寫字母開頭,React通過這個特點來判斷是不是一個組件
注意:2 函數必須有返回值,返回值可以是:JSX對象或null
注意:3 返回的JSX,必須有一個根元素
注意:4 組件的返回值使用()包裹,避免換行問題
function Welcome(props) { return ( // 此處注釋的寫法class創建{/* 此處 注釋的寫法 必須要{}包裹 */}) } ReactDOM.render(Shopping List for {props.name}
, document.getElementById("app") )
在es6中class僅僅是一個語法糖,不是真正的類,本質上還是構造函數+原型 實現繼承
// ES6中class關鍵字的簡單使用 // - **ES6中的所有的代碼都是運行在嚴格模式中的** // - 1 它是用來定義類的,是ES6中實現面向對象編程的新方式 // - 2 使用`static`關鍵字定義靜態屬性 // - 3 使用`constructor`構造函數,創建實例屬性 // - [參考](http://es6.ruanyifeng.com/#docs/class) // 語法: class Person { // 實例的構造函數 constructor constructor(age){ // 實例屬性 this.age = age } // 在class中定義方法 此處為實例方法 通過實例打點調用 sayHello () { console.log("大家好,我今年" + this.age + "了"); } // 靜態方法 通過構造函數打點調用 Person.doudou() static doudou () { console.log("我是小明,我新get了一個技能,會暖床"); } } // 添加靜態屬性 Person.staticName = "靜態屬性" // 實例化對象 const p = new Person(19) // 實現繼承的方式 class American extends Person { constructor() { // 必須調用super(), super表示父類的構造函數 super() this.skin = "white" this.eyeColor = "white" } } // 創建react對象 // 注意:基于 `ES6` 中的class,需要配合 `babel` 將代碼轉化為瀏覽器識別的ES5語法 // 安裝:`npm i -D babel-preset-env` // react對象繼承字React.Component class ShoppingList extends React.Component { constructor(props) { super(props) } // class創建的組件中 必須有rander方法 且顯示return一個react對象或者null render() { return (給組件傳遞數據 - 父子組件傳遞數據) } }Shopping List for {this.props.name}
組件中有一個 只讀的對象 叫做 props,無法給props添加屬性
獲取方式:函數參數 props
作用:將傳遞給組件的屬性轉化為 props 對象中的屬性
function Welcome(props){ // props ---> { username: "zs", age: 20 } return (封裝組件到獨立的文件中) } // 給 Hello組件 傳遞 props:username 和 age(如果你想要傳遞numb類型是數據 就需要向下面這樣) ReactDOM.reander(Welcome React姓名:{props.username}----年齡是:{props.age}
, ......)
// 創建Hello2.js組件文件 // 1. 引入React模塊 // 由于 JSX 編譯后會調用 React.createElement 方法,所以在你的 JSX 代碼中必須首先拿到React。 import React from "react" // 2. 使用function構造函數創建組件 function Hello2(props){ return (props和state props) } // 3. 導出組件 export default Hello2 // app.js中 使用組件: import Hello2 from "./components/Hello2"這是Hello2組件這是大大的H1標簽,我大,我驕傲!!!
這是小小的h6標簽,我小,我傲嬌!!!
作用:給組件傳遞數據,一般用在父子組件之間
說明:React把傳遞給組件的屬性轉化為一個對象并交給 props
特點:props是只讀的,無法給props添加或修改屬性
props.children:獲取組件的內容,比如:
// props 是一個包含數據的對象參數,不要試圖修改 props 參數 // 返回值:react元素 function Welcome(props) { // 返回的 react元素中必須只有一個根元素 returnstatehello, {props.name}} class Welcome extends React.Component { constructor(props) { super(props) } render() { returnHello, {this.props.name}
} }
狀態即數據
作用:用來給組件提供組件內部使用的數據
注意:只有通過class創建的組件才具有狀態
注意:狀態是私有的,完全由組件來控制
注意:不要在 state 中添加 render() 方法中不需要的數據,會影響渲染性能!
可以將組件內部使用但是不渲染在視圖中的內容,直接添加給 this
注意:不要在 render() 方法中調用 setState() 方法來修改state的值
但是可以通過 this.state.name = "rose" 方式設置state(不推薦!!!!)
// 例: class Hello extends React.Component { constructor() { // es6繼承必須用super調用父類的constructor super() this.state = { gender: "male" } } render() { return (JSX語法轉化過程性別:{ this.state.gender }) } }
// 1、JSX const element = (評論列表案例Hello, world!
) // 2、JSX -> createElement const element = React.createElement( "h1", {className: "greeting"}, "Hello, world!" ) // React elements: 使用對象的形式描述頁面結構 // Note: 這是簡化后的對象結構 const element = { type: "h1", props: { className: "greeting", }, children: ["Hello, world"] }
鞏固有狀態組件和無狀態組件的使用
兩個組件:
[ { user: "張三", content: "哈哈,沙發" }, { user: "張三2", content: "哈哈,板凳" }, { user: "張三3", content: "哈哈,涼席" }, { user: "張三4", content: "哈哈,磚頭" }, { user: "張三5", content: "哈哈,樓下山炮" } ] // 屬性擴展style樣式
// 1. 直接寫行內樣式:// 2. 抽離為對象形式 var styleH3 = {color:"blue"} var styleObj = { liStyle:{border:"1px solid red", fontSize:"12px"}, h3Style:{color:"green"} }
評論人:{props.user}
相關文章React數據流和組件間的溝通總結
單向數據流和雙向綁定各有什么優缺點?
怎么更好的理解虛擬DOM?
React中文文檔
React 源碼剖析系列 - 不可思議的 react diff
深入淺出React(四):虛擬DOM Diff算法解析
組件的生命周期簡單說:一個組件從開始到最后消亡所經歷的各種狀態,就是一個組件的生命周期
組件生命周期函數的定義:從組件被創建,到組件掛載到頁面上運行,再到頁面關閉組件被卸載,這三個階段總是伴隨著組件各種各樣的事件,那么這些事件,統稱為組件的生命周期函數!
通過這個函數,能夠讓開發人員的代碼,參與到組件的生命周期中。也就是說,通過鉤子函數,就可以控制組件的行為
react component
React Native 中組件的生命周期
React 生命周期的管理藝術
智能組件和木偶組件
組件生命周期函數總覽組件的生命周期包含三個階段:創建階段(Mounting)、運行和交互階段(Updating)、卸載階段(Unmounting)
Mounting:
constructor()
componentWillMount()
render()
componentDidMount()
Updating
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
Unmounting
componentWillUnmount()組件生命周期 - 創建階段(Mounting)
特點:該階段的函數只執行一次
constructor()作用:1 獲取props 2 初始化state
說明:通過 constructor() 的參數props獲取
設置state和props
class Greeting extends React.Component { constructor(props) { // 獲取 props super(props) // 初始化 state this.state = { count: props.initCount } } } // 初始化 props // 語法:通過靜態屬性 defaultProps 來初始化props Greeting.defaultProps = { initCount: 0 };componentWillMount()
說明:組件被掛載到頁面之前調用,其在render()之前被調用,因此在這方法里同步地設置狀態將不會觸發重渲染
注意:無法獲取頁面中的DOM對象
注意:可以調用 setState() 方法來改變狀態值
用途:發送ajax請求獲取數據
componentWillMount() { console.warn(document.getElementById("btn")) // null this.setState({ count: this.state.count + 1 }) }render()
作用:渲染組件到頁面中,無法獲取頁面中的DOM對象
注意:不要在render方法中調用 setState() 方法,否則會遞歸渲染
原因說明:狀態改變會重新調用render(),render()又重新改變狀態
render() { console.warn(document.getElementById("btn")) // null return (componentDidMount(){ this.state.count === 4 ? null :) }}
1 組件已經掛載到頁面中
2 可以進行DOM操作,比如:獲取到組件內部的DOM對象
3 可以發送請求獲取數據
4 可以通過 setState() 修改狀態的值
注意:在這里修改狀態會重新渲染
componentDidMount() { // 此時,就可以獲取到組件內部的DOM對象 console.warn("componentDidMount", document.getElementById("btn")) }組件生命周期 - 運行階段(Updating)
特點:該階段的函數執行多次
說明:每當組件的props或者state改變的時候,都會觸發運行階段的函數
componentWillReceiveProps()說明:組件接受到新的props前觸發這個方法
參數:當前組件props值
可以通過 this.props 獲取到上一次的值
使用:若你需要響應屬性的改變,可以通過對比this.props和nextProps并在該方法中使用this.setState()處理狀態改變
注意:修改state不會觸發該方法
componentWillReceiveProps(nextProps) { console.warn("componentWillReceiveProps", nextProps) }shouldComponentUpdate()
作用:根據這個方法的返回值決定是否重新渲染組件,返回true重新渲染,否則不渲染
優勢:通過某個條件渲染組件,降低組件渲染頻率,提升組件性能
說明:如果返回值為false,那么,后續render()方法不會被調用
注意:這個方法必須返回布爾值!!!
場景:根據隨機數決定是否渲染組件
// - 參數: // - 第一個參數:最新屬性對象 // - 第二個參數:最新狀態對象 shouldComponentUpdate(nextProps, nextState) { console.warn("shouldComponentUpdate", nextProps, nextState) return nextState.count % 2 === 0 }componentWillUpdate()
作用:組件將要更新
參數:最新的屬性和狀態對象
注意:不能修改狀態 否則會循環渲染
componentWillUpdate(nextProps, nextState) { console.warn("componentWillUpdate", nextProps, nextState) }render() 渲染
作用:重新渲染組件,與Mounting階段的render是同一個函數
注意:這個函數能夠執行多次,只要組件的屬性或狀態改變了,這個方法就會重新執行
componentDidUpdate()作用:組件已經被更新
參數:舊的屬性和狀態對象
componentDidUpdate(prevProps, prevState) { console.warn("componentDidUpdate", prevProps, prevState) }組件生命周期 - 卸載階段(Unmounting)
組件銷毀階段:組件卸載期間,函數比較單一,只有一個函數,這個函數也有一個顯著的特點:組件一輩子只能執行依次!
使用說明:只要組件不再被渲染到頁面中,那么這個方法就會被調用( 渲染到頁面中 -> 不再渲染到頁面中 )
componentWillUnmount()
作用:在卸載組件的時候,執行清理工作,比如
1 清除定時器
2 清除componentDidMount創建的DOM對象
React - createClass(不推薦)React.createClass({}) 方式,創建有狀態組件,該方式已經被廢棄!!!
通過導入 require("create-react-class"),可以在不適用ES6的情況下,創建有狀態組件
getDefaultProps() 和 getInitialState() 方法:是 createReactClass() 方式創建組件中的兩個函數
React without ES6
React 不適用ES6
var createReactClass = require("create-react-class"); var Greeting = createReactClass({ // 初始化 props getDefaultProps: function() { console.log("getDefaultProps"); return { title: "Basic counter!!!" } }, // 初始化 state getInitialState: function() { console.log("getInitialState"); return { count: 0 } }, render: function() { console.log("render"); return (state和setState); }, handleIncrement: function() { var newCount = this.state.count + 1; this.setState({count: newCount}); }, propTypes: { title: React.PropTypes.string } }); ReactDOM.render( React.createElement(Greeting), document.getElementById("app") );{this.props.title}
{this.state.count}
注意:使用 setState() 方法修改狀態,狀態改變后,React會重新渲染組件
注意:不要直接修改state屬性的值,這樣不會重新渲染組件!!!
使用:1 初始化state 2 setState修改state
// 修改state(不推薦使用) // https://facebook.github.io/react/docs/state-and-lifecycle.html#do-not-modify-state-directly this.state.test = "這樣方式,不會重新渲染組件";
constructor(props) { super(props) // 正確姿勢!!! // -------------- 初始化 state -------------- this.state = { count: props.initCount } } componentWillMount() { // -------------- 修改 state 的值 -------------- // 方式一: this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }, function(){ // 由于 setState() 是異步操作,所以,如果想立即獲取修改后的state // 需要在回調函數中獲取 // https://doc.react-china.org/docs/react-component.html#setstate }); // 方式二: this.setState(function(prevState, props) { return { counter: prevState.counter + props.increment } }) // 或者 - 注意: => 后面需要帶有小括號,因為返回的是一個對象 this.setState((prevState, props) => ({ counter: prevState.counter + props.increment })) }組件綁定事件
1 通過React事件機制 onClick 綁定
2 JS原生方式綁定(通過 ref 獲取元素)
注意:ref 是React提供的一個特殊屬性
ref的使用說明:react ref
React中的事件機制 - 推薦注意:事件名稱采用駝峰命名法
例如:onClick 用來綁定單擊事件
JS原生方式 - 知道即可說明:給元素添加 ref 屬性,然后,獲取元素綁定事件
// JSX // 將當前DOM的引用賦值給 this.txtInput 屬性 this.txtInput = input } type="button" value="我是豆豆" /> componentDidMount() { // 通過 this.txtInput 屬性獲取元素綁定事件 this.txtInput.addEventListener(() => { this.setState({ count:this.state.count + 1 }) }) }事件綁定中的this
1 通過 bind 綁定
2 通過 箭頭函數 綁定
通過bind綁定原理:bind能夠調用函數,改變函數內部this的指向,并返回一個新函數
說明:bind第一個參數為返回函數中this的指向,后面的參數為傳給返回函數的參數
// 自定義方法: handleBtnClick(arg1, arg2) { this.setState({ msg: "點擊事件修改state的值" + arg1 + arg2 }) } render() { return () }{this.state.msg}
在構造函數中使用bind
constructor() { super() this.handleBtnClick = this.handleBtnClick.bind(this) } // render() 方法中:通過箭頭函數綁定
原理:箭頭函數中的this由所處的環境決定,自身不綁定this
{ this.handleBtnClick("參數1", "參數2") } } /> handleBtnClick(arg1, arg2) { this.setState({ msg: "在構造函數中綁定this并傳參" + arg1 + arg2 }); }受控組件
表單和受控組件
非受控組件
在HTML當中,像input,textarea和select這類表單元素會維持自身狀態,并根據用戶輸入進行更新。
在React中,可變的狀態通常保存在組件的state中,并且只能用 setState() 方法進行更新.
React根據初始狀態渲染表單組件,接受用戶后續輸入,改變表單組件內部的狀態。
因此,將那些值由React控制的表單元素稱為:受控組件。
受控組件的特點:
1 表單元素
2 由React通過JSX渲染出來
3 由React控制值的改變,也就是說想要改變元素的值,只能通過React提供的方法來修改
注意:只能通過setState來設置受控組件的值
// 模擬實現文本框數據的雙向綁定 // 當文本框內容改變的時候,觸發這個事件,重新給state賦值 handleTextChange = event => { console.log(event.target.value) this.setState({ msg: event.target.value }) }評論列表案例
[ {name: "小明", content: "沙發!!!"}, {name: "小紅", content: "小明,居然是你"}, {name: "小剛", content: "小明,放學你別走!!!"}, ]props校驗
作用:通過類型檢查,提高程序的穩定性
命令:npm i -S prop-types
類型校驗文檔
使用:給類提供一個靜態屬性 propTypes(對象),來約束props
// 引入模塊 import PropTypes from "prop-types" // ...以下代碼是類的靜態屬性: // propTypes 靜態屬性的名稱是固定的!!! static propTypes = { initCount: PropTypes.number, // 規定屬性的類型 initAge: PropTypes.number.isRequired // 規定屬性的類型,且規定為必傳字段 }React 單向數據流
React 中采用單項數據流
數據流動方向:自上而下,也就是只能由父組件傳遞到子組件
數據都是由父組件提供的,子組件想要使用數據,都是從父組件中獲取的
如果多個組件都要使用某個數據,最好將這部分共享的狀態提升至他們最近的父組件當中進行管理
單向數據流
狀態提升
react中的單向數據流動: 1 數據應該是從上往下流動的,也就是由父組件將數據傳遞給子組件 2 數據應該是由父組件提供,子組件要使用數據的時候,直接從子組件中獲取 在我們的評論列表案例中:數據是由CommentList組件(父組件)提供的 子組件 CommentItem 負責渲染評論列表,數據是由 父組件提供的 子組件 CommentForm 負責獲取用戶輸入的評論內容,最終也是把用戶名和評論內容傳遞給了父組件,由父組件負責處理這些數據( 把數據交給 CommentItem 由這個組件負責渲染 )組件通訊
父 -> 子:props
子 -> 父:父組件通過props傳遞回調函數給子組件,子組件調用函數將數據作為參數傳遞給父組件
兄弟組件:因為React是單向數據流,因此需要借助父組件進行傳遞,通過父組件回調函數改變兄弟組件的props
React中的狀態管理: flux(提出狀態管理的思想) -> Redux -> mobx
Vue中的狀態管理: Vuex
簡單來說,就是統一管理了項目中所有的數據,讓數據變的可控
組件通訊
Context特性
注意:如果不熟悉React中的數據流,不推薦使用這個屬性
這是一個實驗性的API,在未來的React版本中可能會被更改
作用:跨級傳遞數據(爺爺給孫子傳遞數據),避免向下每層手動地傳遞props
說明:需要配合PropTypes類型限制來使用
class Grandfather extends React.Component { // 類型限制(必須),靜態屬性名稱固定 static childContextTypes = { color: PropTypes.string.isRequired } // 傳遞給孫子組件的數據 getChildContext() { return { color: "red" } } render() { return (react-router) } } class Child extends React.Component { // 類型限制,靜態屬性名字固定 static contextTypes = { color: PropTypes.string } render() { return ( // 從上下文對象中獲取爺爺組件傳遞過來的數據 爺爺告訴文字是紅色的
) } } class Father extends React.Component { render() { return () } }
react router 官網
react router github
安裝:npm i -S react-router-dom
基本概念說明Router組件本身只是一個容器,真正的路由要通過Route組件定義
使用步驟1 導入路由組件
2 使用
在整個應用程序中,只需要使用一次
3 使用 作為鏈接地址,并指定to屬性
4 使用
// 1 導入組件 import { HashRouter as Router, Link, Route } from "react-router-dom" // 2 使用注意點// 3 設置 Link 首頁 電影 關于 // 4 設置 Route // exact 表示:絕對匹配(完全匹配,只匹配:/)
:類似于vue中的
配置:通過Route中的path屬性來配置路由參數
獲取:this.props.match.params 獲取
// 配置路由參數路由跳轉// 獲取路由參數 const type = this.props.match.params.movieType
react router - history
history.push() 方法用于在JS中實現頁面跳轉
history.go(-1) 用來實現頁面的前進(1)和后退(-1)
this.props.history.push("/movie/movieDetail/" + movieId)fetch
作用:Fetch 是一個現代的概念, 等同于 XMLHttpRequest。它提供了許多與XMLHttpRequest相同的功能,但被設計成更具可擴展性和高效性。
fetch() 方法返回一個Promise對象
fetch 基本使用fetch Response
fetch 介紹
Javascript 中的神器——Promise
/* 通過fetch請求回來的數據,是一個Promise對象. 調用then()方法,通過參數response,獲取到響應對象 調用 response.json() 方法,解析服務器響應數據 再次調用then()方法,通過參數data,就獲取到數據了 */ fetch("/api/movie/" + this.state.movieType) // response.json() 讀取response對象,并返回一個被解析為JSON格式的promise對象 .then((response) => response.json()) // 通過 data 獲取到數據 .then((data) => { console.log(data); this.setState({ movieList: data.subjects, loaing: false }) })跨域獲取數據的三種常用方式
1 JSONP
2 代理
3 CORS
JSONP安裝:npm i -S fetch-jsonp
利用JSONP實現跨域獲取數據,只能獲取GET請求
fetch-jsonp
fetch-jsonp
限制:1 只能發送GET請求 2 需要服務端支持JSONP請求
/* movielist.js */ fetchJsonp("https://api.douban.com/v2/movie/in_theaters") .then(rep => rep.json()) .then(data => { console.log(data) })代理
webpack-dev-server 代理配置如下:
問題:webpack-dev-server 是開發期間使用的工具,項目上線了就不再使用 webpack-dev-server
解決:項目上線后的代碼,也是會部署到一個服務器中,這個服務器配置了代理功能即可(要求兩個服務器中配置的代理規則相同)
// webpack-dev-server的配置 devServer: { // https://webpack.js.org/configuration/dev-server/#devserver-proxy // https://github.com/chimurai/http-proxy-middleware#http-proxy-options // http://www.jianshu.com/p/3bdff821f859 proxy: { // 使用:/api/movie/in_theaters // 訪問 ‘/api/movie/in_theaters’ ==> "https://api.douban.com/v2/movie/in_theaters" "/api": { // 代理的目標服務器地址 target: "https://api.douban.com/v2", // https請求需要該設置 secure: false, // 必須設置該項 changeOrigin: true, // "/api/movie/in_theaters" 路徑重寫為:"/movie/in_theaters" pathRewrite: {"^/api" : ""} } } } /* movielist.js */ fetch("/api/movie/in_theaters") .then(function(data) { // 將服務器返回的數據轉化為 json 格式 return data.json() }) .then(function(rep) { // 獲取上面格式化后的數據 console.log(rep); })CORS - 服務器端配合
示例:NodeJS設置跨域
跨域資源共享 CORS 詳解 - 阮一峰
// 通過Express的中間件來處理所有請求 app.use("*", function (req, res, next) { // 設置請求頭為允許跨域 res.header("Access-Control-Allow-Origin", "*"); // 設置服務器支持的所有頭信息字段 res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization,Accept,X-Requested-With"); // 設置服務器支持的所有跨域請求的方法 res.header("Access-Control-Allow-Methods", "POST,GET"); // next()方法表示進入下一個路由 next(); });redux
狀態管理工具,用來管理應用中的數據
核心
Action:行為的抽象,視圖中的每個用戶交互都是一個action
比如:點擊按鈕
Reducer:行為響應的抽象,也就是:根據action行為,執行相應的邏輯操作,更新state
比如:點擊按鈕后,添加任務,那么,添加任務這個邏輯放到 Reducer 中
1 創建State
Store:
1 Redux應用只能有一個store
2 getState():獲取state
3 dispatch(action):更新state
/* action */ // 在 redux 中,action 就是一個對象 // action 必須提供一個:type屬性,表示當前動作的標識 // 其他的參數:表示這個動作需要用到的一些數據 { type: "ADD_TODO", name: "要添加的任務名稱" } // 這個動作表示要切換任務狀態 { type: "TOGGLE_TODO", id: 1 }
/* reducer */ // 第一個參數:表示狀態(數據),我們需要給初始狀態設置默認值 // 第二個參數:表示 action 行為 function todo(state = [], action) { switch(action.type) { case "ADD_TODO": state.push({ id: Math.random(), name: action.name, completed: false }) return state case "TOGGLE_TODO": for(var i = 0; i < state.length; i++) { if (state[i].id === action.id) { state[i].completed = !state[i].completed break } } return state default: return state } } // 要執行 ADD_TODO 這個動作: dispatch( { type: "ADD_TODO", name: "要添加的任務名稱" } ) // 內部會調用 reducer todo(undefined, { type: "ADD_TODO", name: "要添加的任務名稱" })
推薦大家使用Fundebug,一款很好用的BUG監控工具~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92630.html
摘要:如果遇到非常的復雜的匹配,正則表達式的優勢就更加明顯了。關于正則表達式書寫規則,可查看,上面說的很清楚了,我就不貼出來了。替換與正則表達式匹配的子串,并返回替換后的字符串。結語正則表達式并不難,懂了其中的套路之后,一切都變得簡單了。 前言 在正文開始前,先說說正則表達式是什么,為什么要用正則表達式?正則表達式在我個人看來就是一個瀏覽器可以識別的規則,有了這個規則,瀏覽器就可以幫我們判斷...
摘要:從入門到放棄是什么,黑歷史,不講,自己百度去。類你沒有看錯,這里面的就沒有問題的。之前我們用過,和有了,再也不用這兩個貨了。一個函數,可以遍歷狀態感覺就是狀態機,好吧不說了再說就懵逼了。 ES6從入門到放棄 1.ES6是什么,黑歷史,不講,自己百度去。 2.在瀏覽器中如何使用? 1.babel babeljs.io在線編譯 2.traceur-----Google出的編譯器,把E...
摘要:但監聽器要在事件源上實現接口也就是說,直接用一個類實現和接口是監聽不到內對象的變化的。 什么是監聽器 監聽器就是一個實現特定接口的普通java程序,這個程序專門用于監聽另一個java對象的方法調用或屬性改變,當被監聽對象發生上述事件后,監聽器某個方法將立即被執行。。 為什么我們要使用監聽器? 監聽器可以用來檢測網站的在線人數,統計網站的訪問量等等! 監聽器組件 監聽器涉及三個組件:事件...
摘要:注解在類上為類提供一個全參的構造方法,加了這個注解后,類中不提供默認構造方法了。這個注解用在類上,使用類中所有帶有注解的或者帶有修飾的成員變量生成對應的構造方法。 轉載請注明原創地址:http://www.54tianzhisheng.cn/2018/01/07/lombok/ showImg(http://ohfk1r827.bkt.clouddn.com/blog/180107/7...
摘要:縮進不一致,會導致運行錯誤。變量變量在使用前必須先定義即賦予變量一個值,否則會報錯數據類型布爾只有和兩個值,表示真或假。 簡介 Python 是一種高層次的結合了解釋性、編譯性、互動性和面向對象的腳本語言。Python 由 Guido van Rossum 于 1989 年底在荷蘭國家數學和計算機科學研究所發明,第一個公開發行版發行于 1991 年。 特點 易于學習:Python ...
摘要:動態地代理,可以猜測一下它的含義,在運行時動態地對某些東西代理,代理它做了其他事情。所以動態代理的內容重點就是這個。所以下一篇我們來細致了解下的到底是怎么使用動態代理的。 之前講了《零基礎帶你看Spring源碼——IOC控制反轉》,本來打算下一篇講講Srping的AOP的,但是其中會涉及到Java的動態代理,所以先單獨一篇來了解下Java的動態代理到底是什么,Java是怎么實現它的。 ...
閱讀 3523·2021-11-18 10:02
閱讀 954·2021-09-04 16:48
閱讀 2041·2019-08-30 15:55
閱讀 3544·2019-08-30 15:52
閱讀 1818·2019-08-30 14:08
閱讀 3561·2019-08-30 13:19
閱讀 1144·2019-08-27 10:53
閱讀 3124·2019-08-26 12:11