本文寫的倉促,算是一個學習筆記吧,算是一個入門級的學習文章。若是你剛剛入門,那麼可能一些入門的視頻可能更加適合你。但若是具有一些知識,好比Vue
,那麼視頻就不適合了。建議看完本篇文章在腦海中過一遍映像,在去官網深讀,和一些深刻文章,想來會有很是好的提高。css
「一個框架不是看幾篇文章,寫寫Demo就能說本身會,熟悉。須要不斷實踐,踩坑,學習原理。多想才能掌握。我只是結合
- - QAQVue
進行的React
學習,只是冰山一角罷了。充其量只是API
的搬運工。react
新手仍是推薦官方的腳手架,經過npx
來進行項目的初始化一個demo項目。git
npx create-react-app 項目名稱
複製代碼
默認生成的目錄狀況下,項目的解構就是這樣的。github
Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 20.6.15 14:21 public d----- 20.6.15 16:41 src -a---- 20.6.15 14:21 310 .gitignore -a---- 20.6.15 14:22 746 package.json -a---- 20.6.15 14:21 2884 README.md -a---- 20.6.15 14:22 526017 yarn.lock 複製代碼
隨後經過npm
或者 yarn
來將項目跑起來。執行shell
後會自動打開一個瀏覽器,當看到localhost:3000
渲染後。那麼就能夠開啓React大門了web
# npm shell 命令
npm run start # yarn shell 命令 yarn start 複製代碼
在Vue
中template
模板獲得大量的使用,只要你會寫HTML
那麼應該難不倒你這個小機靈鬼。而React
則是使用了在函數中直接返回DOM
。看起來很是的神奇,也致使了一些小夥伴在入門的時候會有點摸不着頭腦,可是若是有必定基礎,在Vue
中寫過了Render
函數的話,我想上手起來仍是很是容易的。它看起來是下面這個樣子的。其本質上就是一個createElement
的過程。因此,將這種模板的渲染方式稱之爲JSX
。shell
import React from 'react';
import './App.css'; function App() { return ( <div className="App"> <h1>你好呀</h1> <p>今天又是充滿但願的一天...</p> </div> ); } export default App; 複製代碼
經過React
的JSX模板引擎,最終將其渲染到DOM上npm
在Vue
的模板中,經過{{}}
兩個花括號來聲明約束,表示這個聲明中的字段是一個js的值,而不是一個文本。在React則是使用了{}
一個花括號來作約定。那麼就能夠在DOM
中使用js
了。下面是一個Class
組件,將state
的text
值綁定在DOM
的。json
class App extends React.Component {
constructor (props) { super(props) this.state = { text: '我是wangly19' } } updateText () { this.setState({ text: '我是帥氣的wangly19' }) } render () { return ( <div className="App"> <p>我是一個動態的數據: {this.state.text}</p> <button onClick={ this.updateText.bind(this) }>更換</button> </div> ) } } 複製代碼
在Vue
中,若是須要動態的渲染一個節點,是經過v-if
指令來實現的,在React中呢,可使用運算符來渲染元素。經過Vue
來作一個對比吧。redux
「經過
- - QAQ&&(或)
運算符來達到v-if
的同樣效果。數組
render () {
return ( <div className="App"> <p>我是一個動態的數據: {this.state.text}</p> {/* { <p v-if="true">2</p> } */} {true && <p>2</p>} </div> ) } 複製代碼
「經過三元運算符能夠來達到
- - QAQv-if
和v-else
同樣的效果。
render () {
return ( <div className="App"> <p>我是一個動態的數據: {this.state.text}</p> {/* { <p v-if="true">2</p> } */} {true ? <p>true</p> : <p>false</p>} </div> ) } 複製代碼
經過map
方法來遍歷一些基本數據結構的節點。
「經過數據結構自帶的map能夠遍歷出
- - QAQvalue
,index
,key
在return
中返回節點信息。
在JavaScript
中,經過onClick
來綁定一個事件。
<button onclick="activeBuff">激活按鈕</button>
複製代碼
而在jsx中,則是經過onClick
屬性,且後面加一個jsx渲染模板的方式。
「須要注意的是,
- - QAQClass組件
下的this
是不存在的,須要用戶手動爲方法綁定this,在調用的點擊事件方法。
<button onClick={ this.activeBuff.bind(this) }>激活按鈕</button> 複製代碼
衆所周知,Vue
和React
都是組件化解決方案,那麼在React
中是如何建立一個組件的呢?在React
新版本中,推出了React Hooks
方案。因此如今主流的仍是Class
組件和Function
組件。
Class組件的建立方式很是的簡單,只須要建立一個Class
類而且讓它繼承React.Component
,在Render
方法中return
出JSX的模板。
同時經過構造函數,處理Props
。而且聲明state
狀態初始化一個對象,將Props
掛載到super
上。
class App extends React.Component {
constructor (props) { super(props) this.state = { } } // render函數 render () { return ( <div className="App"> <p>我是Class組件</p> </div> ) } } 複製代碼
隨着React Hooks
發佈,開發的主流也漸漸的轉入了函數組件,不過Class
組件在舊項目中仍是會用的。因此都學習一下。對比Class組件,函數組件就很是的簡單了。在函數內部返回一個render模板就OK了。以下:
import React from 'react'
function FunctionDemo () { return ( <div> 我是函數組件 </div> ) } export default FunctionDemo 複製代碼
這裏着重的開個單章,主要是Class
組件中的State
值更改,由於函數組件最好使用的是hooks
,因此單拎出來主要解一下Class
組件下State
狀態。在React
不建議直接修改State
的值,而是使用setState
的方式更新狀態。
this.setState({
default: '修改後的文件' }) 複製代碼
一樣的,setState
後當前的值並不會直接改變。它是一個異步函數,在異步函數中能夠拿到最新的狀態。
若是須要進行計算值的累加,推薦使用的是經過函數的返回值形式。
「這裏的原理相似
- - QAQVue
的組件data
的函數return
方式。 若是使用對象方式的話,在多個setState
使用的話會被後面的任務覆蓋,從而直接執行一次
// no
this.setState({ index: this.state.index + 1 }); this.setState({ index: this.state.index + 1 }); // yes this.setState({ index: this.state.index + 1 }); this.setState({ index: this.state.index + 1 }); this.setState((prevState, props) => { return {quantity: prevState.quantity + 1}; }); 複製代碼
組件通訊是開發中常常用到的功能,可謂是靈魂之一了。那麼React的組件通訊是如何完成的呢?
經過Props
可使子組件很是快捷的拿到父組件的傳遞過去的內容。
<ClassDemo name="wangly19"></ClassDemo>
複製代碼
constructor (props) {
super(props) this.state = { defaultText: '我是默認的文字' } } 複製代碼
經過this.props.父組件綁定的屬性名稱
<p>{ this.props.name }</p> 複製代碼
在Vue
中能夠定義Props
的默認值,哪怕用戶沒有傳遞,就會顯示默認Props
中定義的內容。
ClassDemo.defaultProps = {
name: '我是默認的名稱' // ... 參數列表 } 複製代碼
經過Props
傳遞一個函數,當子組件須要改變父組件的值時,經過this.props.[函數]
執行回調。
// 父組件
class App extends React.Component { constructor (props) { super(props) this.state = { childMessage: '2222222222222222' } } onPropChange (newVal) { this.setState({ childMessage: newVal }) } render () { return ( <div className="App"> <p>{ this.state.childMessage }</p> <ClassDemo onPropChange={ this.onPropChange.bind(this) }></ClassDemo> {/* <FunctionDemo></FunctionDemo> */} </div> ) } } 複製代碼
import React from 'react';
class ClassDemo extends React.Component { constructor (props) { super(props) this.state = { defaultText: '我是默認的文字' } } changeText () { this.props.onPropChange('111111111111111') } render () { return ( <div className="App"> <button onClick={ this.changeText.bind(this) }>更改文本</button> </div> ) } } export default ClassDemo; 複製代碼
看了官方的生命週期介紹,挺簡潔的。分別是組件模板選而後,已經準備就緒的時候,能夠作組件加載後的一些邏輯操做,鎮樓神圖。
構造函數初始化,最早被執行,初始化State
等等。
這是一個靜態方法,須要在前面增長static
的屬性
渲染函數,返回渲染的內容,當頁面產生更新也會觸發該方法。
組件掛載以後,這個時候組件已經掛載完畢了
組件即將被更新,這裏參數分別對應先後被修改的內容,經過返回一個布爾值告知是否須要更新視圖。
當視圖更新,那麼Render
也會從新更新
getSnapshotBeforeUpdate
在render
以後componentDidUpdate
以前輸出,相似於中間件用來作一些捕獲操做。
getSnapshotBeforeUpdate
,有三個參數prevProps
,prevState
,snapshot
,表示以前的props
,以前的state
,和snapshot
。snapshot
是getSnapshotBeforeUpdate
返回的值
constructor (props) {
super(props) this.state = {} console.log('1.constructor構造函數') } componentDidMount () { console.log('componentDidMount') Store.subscribe(() => { this.setState({}) }) } static getDerivedStateFromProps (nextProps, prevState) { console.log('getDerivedStateFromProps') console.log(nextProps, prevState) return true } getSnapshotBeforeUpdate (prevProps, prevState) { console.log(prevProps, prevState) return 'top: 200' } componentDidUpdate (prevProps, prevState, snapshot) { console.log(prevProps, prevState, snapshot) } componentWillUnmount () { console.log('componentWillUnmount') } changeText () { Store.dispatch({ type: 'changeName', value: '我是ClassDemo中修改的名字: wangly' }) } render () { console.log('3.render函數') return ( <div className="App"> <p>{ Store.getState().redux_name }</p> { this.state.redux_name } <button onClick={ this.changeText.bind(this) }>更改文本</button> </div> ) } 複製代碼
組件卸載,咱們能夠清除一些定時器,取消網絡請求。
插槽對於Vue來講並非很陌生,在React
中插入的節點會以Props
的方式傳遞。能夠經過pro1ps.children
找到而且渲染出來。
// 父親組件
<ClassDemo onPropChange={this.onPropChange.bind(this)}> <h1>插入的元素 </h1> </ClassDemo> // 子組件 <div className="App"> {this.props.children} <button onClick={this.changeText.bind(this)}>更改文本</button> </div> 複製代碼
路由對於SPA應用來說可謂是重中之重,沒有它的話,那麼這個頁面也就不能成爲應用,只能稱之爲頁面。二者可謂天差地別。
# shell
npm install react-router-dom --save 複製代碼
在Vue中都知道路由的mode
有兩種,一種是hash
一種是history
模式。分別以下,經過引入不一樣的包來建立不一樣的Router
。
// histoty import { BrowserRouter as Router, Link, Route } from 'react-router-dom'; // hash import { Link, Route, HashRouter as Router } from 'react-router-dom'; 複製代碼
經過as出來的Router
包裹路由快,經過Link
做爲跳轉的行爲容器。這樣一個基本的路由容器就完成。
「須要經過使
- - QAQRoute
進行對組件的聲明配置,才能被Link
找到哦。
import React from 'react';
// histoty import { BrowserRouter as Router, Link, Route } from 'react-router-dom'; // hash // import { Link, Route, HashRouter as Router } from 'react-router-dom'; function Page1 () { return ( <h1>我是Page1</h1> ) } function Page2 () { return ( <h1>我是Page2</h1> ) } function Page3 () { return ( <h1>我是Page3</h1> ) } class App extends React.Component { constructor (props) { super(props) this.state = { } } render () { return ( <div className="App"> <Router> <ul> <li> <Link to="page1">Page1</Link> </li> <li> <Link to="page2">Page2</Link> </li> <li> <Link to="page3">Page3</Link> </li> </ul> <Route exact path="/page1" component={ Page1 }></Route> <Route exact path="/page2" component={ Page2 }></Route> <Route exact path="/page3" component={ Page3 }></Route> </Router> </div> ) } } export default App; 複製代碼
路由傳遞參數通常使用param
和query
參數。經過給to
傳遞一個對象的方式來進行數據的傳遞。能夠看到,向page1
的路由上添加了一個:id
表示須要傳遞param
的id
的值,同時聲明瞭search
的文本和state對象
多種方式傳遞了參數。以便根據不一樣的場景使用。
;<div className="App"> <Router> <ul> <li> <Link to={{ pathname: '/page1/10', search: '?roles=[10, 20]', state: { name: 'wangly19' }, }} > Page1 </Link> </li> <li> <Link to="page2">Page2</Link> </li> <li> <Link to="page3">Page3</Link> </li> </ul> <Route exact path="/page1/:id" component={Page1}></Route> <Route exact path="/page2" component={Page2}></Route> <Route exact path="/page3" component={Page3}></Route> </Router> </div> 複製代碼
當你使用History
路由的時候,某些時候須要主動的跳轉道某個路由,這個時候又不能去觸發節點行爲,因此這個時候就能夠經過API的方式,進行跳轉。使用方式和Vue
大差不差。
// 跳轉頁面
this.props.history.push(參數和to的內容像素) this.props.history.push('page1') // 重定向頁面 this.props.history.replace('page2') 複製代碼
固然還有hash
的go
方法。
Redux
是相似於Vuex
的一個全局狀態解決方案,它的功能主要是用來存儲公有全局狀態。來方便管理一些共有配置參數,解決業務體積大,結構複雜的項目提供好的狀態管理。
「若是項目不是特別須要,儘可能不去使用它。
- - QAQ
# shell npm install redux --save 複製代碼
看到官方的Demo,是很是容易懂的。下面是官方的代碼,一眼就能看出流程。
import { createStore } from 'redux'
/** * This is a reducer, a pure function with (state, action) => state signature. * It describes how an action transforms the state into the next state. * * The shape of the state is up to you: it can be a primitive, an array, an object, * or even an Immutable.js data structure. The only important part is that you should * not mutate the state object, but return a new object if the state changes. * * In this example, we use a `switch` statement and strings, but you can use a helper that * follows a different convention (such as function maps) if it makes sense for your * project. */ function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } // Create a Redux store holding the state of your app. // Its API is { subscribe, dispatch, getState }. let store = createStore(counter) // You can use subscribe() to update the UI in response to state changes. // Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly. // However it can also be handy to persist the current state in the localStorage. store.subscribe(() => console.log(store.getState())) // The only way to mutate the internal state is to dispatch an action. // The actions can be serialized, logged or stored and later replayed. store.dispatch({ type: 'INCREMENT' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1 複製代碼
// 聲明默認的State狀態值
const modeStore = { redux_name: '我是Redux中聲明的名稱:wangly19' } // 聲明Reducer const reducer = (state = modeStore, action) => { return state } // createStore import { createStore } from 'redux'; import reducer from './reducer' const store = createStore(reducer) export default store 複製代碼
import Store from './index'
<p>{ Store.getState().redux_name }</p> 複製代碼
<button onClick={ this.changeText.bind(this) }>更改文本</button> // dispatch changeText () { Store.dispatch({ type: 'changeName', value: '我是ClassDemo中修改的名字: wangly' }) } 複製代碼
前提是,須要對action
的方法作一個聲明。相似於Vuex的Action
。
const reducer = (state = modeStore, action) => {
switch (action.type) { case 'changeName': const newState = {...state} console.log(state) newState.redux_name = action.value console.log(newState) console.log(state) return newState default: return state; } } 複製代碼
「做爲行爲觸發行爲後更新視圖的憑證。在組件註銷時,注意銷燬它哦。
- - QAQ
componentDidMount () {
/** * 回調函數 */ Store.subscribe(() => { console.log(Store.getState().redux_name) this.setState({}) }) } 複製代碼
「Hooks我準備寫新的文章。
- - QAQ
學習React不少都是以Vue的思路先入個門,不至於一問三不知。也明白了知其一而知其三。若是有基礎那麼學習起來其實並非很困難。可是它的文檔並不如Vue的全面,且對於某些方面來講。花了一天時間整理一些基本的學習東西
「若是以爲對你有幫助,不妨點個贊哦。
- - QAQ
參考資料