redux簡明學習

来源:https://www.cnblogs.com/xiaohuochai/archive/2018/02/15/8447826.html
-Advertisement-
Play Games

[1]核心概念 [2]簡單實例 [3]目錄結構 [4]UI層 [5]非同步 [6]展示和容器 [7]最終結構 ...


前面的話

  這幾天被redux折騰的夠嗆,看了很多視頻,也看了很多資料。很多時候,感覺好像頓悟了,但實際上只是理解了其中的一個小概念而已。真正去做項目的時候,還是會卡殼。可能是學CSS和Javascript時花的時間太久了,學redux的時候有點浮躁。還有就是redux內容實在是不少,全部都看都理解,好像沒什麼必要。不看吧,用的時候總是有點力不從心。於是,決定把這些資料按自己的理解寫成博客,方便自己回憶思路,也希望能幫助到需要的人

 

核心概念

  redux專註於狀態管理,把所有的狀態都存在一個對象中。核心概念包括:store、state、action、reducer

【store】

  store是保存數據的地方,redux提供createStore函數來生成 Store。函數參數是後面要介紹的reducer

import { createStore } from 'redux'
const store = createStore(reducer)

【state】

  state是store的某個時刻的快照,可以通過store.getState()取得當前時刻的state

const state = store.getState()

【action】

  action用來改變state。action是一個對象,其中的type屬性是必須的,其他的屬性一般用來設置改變state需要的數據

const action = {
  type: 'ADD_ONE',
  num: 1
}

  store.dispatch()是發出action的唯一方法

const action = {
  type: 'ADD_ONE',
  num: 1
}
store.dispatch(action)

【reducer】

  reducer 是一個函數,它接受action和當前state作為參數,返回一個新的state

import { createStore } from 'redux'
const store = createStore(reducer)
const reducer = (state = 10, action) => {
  switch (action.type) {
    case 'ADD_ONE':
      return state + action.num;
    default: 
      return state;
  }
};

  當store.dispatch發送過來一個新的action,store就會自動調用reducer,得到新的state

 

簡單實例

  多餘的概念不再介紹,下麵用上面介紹的這四個核心概念實現一個簡單的實例,將create-react-app中index.js文件內容更改如下,即可運行

//第一步,創建action
const addOne = {
  type: 'ADD',
  num: 1
}
const addTwo = {
  type: 'ADD',
  num: 2
}
const square = {
  type: 'SQUARE'
}

//第二步,創建reducer
let math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    default:
      return state
  }
}
//第三步,創建store
import { createStore } from 'redux'
const store = createStore(math)

//第四步,測試,通過dispatch發出action,並通過getState()取得當前state值
console.log(store.getState()) //預設值為10

store.dispatch(addOne) //發起'+1'的action
console.log(store.getState()) //當前值為10+1=11

store.dispatch(square) //發起'乘方'的action
console.log(store.getState()) //當前值為11*11=121

store.dispatch(addTwo) //發起'+2'的action
console.log(store.getState()) //當前值為121+2=123

  結果如下

 

目錄結構

  下麵對目錄結構進行劃分

  1、一般地,將action.type設置為常量,這樣在書寫錯誤時,會得到報錯提示

// constants/ActionTypes.js
export const ADD = 'ADD'
export const SQUARE = 'SQUARE'

  2、可以將addOne對象和addTwo對象整合成add函數的形式

// action/math.js
import { ADD, SQUARE } from '../constants/ActionTypes'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }

  3、根據action.type的分類來拆分reducer,最終通過combineReducers方法將拆分的reducer合併起來。上例中的action類型都是數字運算,無需拆分,只需進行如下變化

// reducer/math.js
import { ADD, SQUARE } from '../constants/ActionTypes'
const math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    default:
      return state
  }
}
export default math
// reducer/index.js
import { combineReducers } from 'redux'
import math from './math'
const rootReducer = combineReducers({
  math
})
export default rootReducer

  4、將store存儲到store/index.js文件中

// store/index.js
import { createStore } from 'redux'
import rootReducer from '../reducer'
export default createStore(rootReducer)

  5、最終,根路徑下的index.js內容如下所示

import store from './store'
import {add, square} from './action/math'

console.log(store.getState()) //預設值為10

store.dispatch(add(1)) //發起'+1'的action
console.log(store.getState()) //當前值為10+1=11

store.dispatch(square) //發起'乘方'的action
console.log(store.getState()) //當前值為11*11=121

store.dispatch(add(2)) //發起'+2'的action
console.log(store.getState()) //當前值為121+2=123

  最終目錄路徑如下所示

  最終結果如下所示

 

UI層

  前面的示例中,只是redux的狀態改變,下麵利用UI層來建立view和state的聯繫,將根目錄下的index.js的內容更改如下

import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square } from './action/math'

ReactDOM.render(
  <div store={store}>
    <p>{store.getState().math}</p>
    <input type="button" onClick={() => store.dispatch(add(1))} value="+1" />
    <input type="button" onClick={() => store.dispatch(add(2))} value="+2" />
    <input type="button" onClick={() => store.dispatch(square)} value="乘方" />
  </div>,
  document.getElementById('root')
)

  雖然可以顯示數字,但是點擊按鈕時,卻不能重新渲染頁面

【store.subscribe()】

  接下來介紹store.subscribe()方法了,該方法用來設置監聽函數,一旦state發生變化,就自動執行這個函數。該方法的返回值是一個函數,調用這個函數可以解除監聽

  下麵將示例代碼更改如下

import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square } from './action/math'

const render = () => ReactDOM.render(
  <div store={store}>
    <p>{store.getState().math}</p>
    <input type="button" onClick={() => store.dispatch(add(1))} value="+1" />
    <input type="button" onClick={() => store.dispatch(add(2))} value="+2" />
    <input type="button" onClick={() => store.dispatch(square)} value="乘方" />
  </div>,
  document.getElementById('root')
)

render()
store.subscribe(render)

  代碼終於可以正常運行了

 

非同步

  redux預設只處理同步,對於API請求這樣的非同步任務則無能為力

  接下來嘗試使用axios的get方法來請求下麵這個API

https://jsonplaceholder.typicode.com/posts/2

  獲取的數據如下

{
  "userId": 1,
  "id": 2,
  "title": "qui est esse",
  "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
}

  然後,將其id值設置為state.math的值

  代碼修改如下

// constants/ActionTypes.js
export const ADD = 'ADD'
export const SQUARE = 'SQUARE'
export const SET = 'SET'

// action/math.js
import { ADD, SQUARE, SET } from '../constants/ActionTypes'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }
export const setNum = num => ({type: SET,num})

// reduce/math.js
import { ADD, SQUARE,SET } from '../constants/ActionTypes'
const math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    case SET:
      return action.num
    default:
      return state
  }
}
export default math

// index.js
import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square, setNum } from './action/math'
import axios from 'axios'
let uri = 'https://jsonplaceholder.typicode.com/posts/2'
const render = () => ReactDOM.render(
  <div store={store}>
    <p>{store.getState().math}</p>
    <input type="button" onClick={() => {axios.get(uri).then(res => {store.dispatch(store.dispatch(setNum(res.data.id)))})}} value="設置Num" />
    <input type="button" onClick={() => store.dispatch(add(1))} value="+1" />
    <input type="button" onClick={() => store.dispatch(add(2))} value="+2" />
    <input type="button" onClick={() => store.dispatch(square)} value="乘方" />
  </div>,
  document.getElementById('root')
)
render()
store.subscribe(render)

  效果如下

  但是,雖然API是非同步操作,但store.dispatch並不是非同步,而axios通過get方法請求回來數據後,store.dispatch在axios中的then方法中同步取得數據

【redux-thunk】

  如果要使用真正的非同步操作,即把axios方法封裝到store.dispatch中,需要使用redux-thunk中間件

  首先,使用npm進行安裝

npm install --save redux-thunk

  然後,使用applyMiddleware來使用thunk中間件

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../reducer'
export default createStore(rootReducer,applyMiddleware(thunk))

  接著來定義setNum這個action creator,然後在index.js文件的DOM載入完成後就發出setNum

  [註意]如果action是一個對象,則它就是一個action,如果action是一個函數,則它是一個action creator,即action製造器

  修改的代碼如下

// action/math.js
import { ADD, SQUARE, SET } from '../constants/ActionTypes'
import axios from 'axios'
const uri = 'https://jsonplaceholder.typicode.com/posts/2'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }
export const setNum = () => (dispatch, getState) => {
  return axios.get(uri).then(res => {
    dispatch({
      type: SET,
      num: res.data.id
    })
  })
}

// index.js
import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square, setNum } from './action/math'
const render = () => ReactDOM.render(
  <div store={store}>
    <p>{store.getState().math}</p>
    <input type="button" onClick={() => store.dispatch(setNum())} value="設置Num" />
    <input type="button" onClick={() => store.dispatch(add(1))} value="+1" />
    <input type="button" onClick={() => store.dispatch(add(2))} value="+2" />
    <input type="button" onClick={() => store.dispatch(square)} value="乘方" />
  </div>,
  document.getElementById('root')
)
render()
store.subscribe(render)

  效果如下

【提示信息】

  如果做的更完備一點,應該把非同步請求時的提示信息也加上。增加一個fetch的action,用於控制fetch過程的提示信息及顯示隱藏情況

  代碼更改如下

// action/fetch.js
import { SET_FETCH_MESSAGE, HIDE_FETCH_MESSAGE } from '../constants/ActionTypes'
export const startFetch = { type: SET_FETCH_MESSAGE,message: '開始發送非同步請求' }
export const successFetch = { type: SET_FETCH_MESSAGE, message: '成功接收數據' }
export const failFetch = { type: SET_FETCH_MESSAGE, message: '接收數據失敗' }
export const hideFetchMessage = { type: HIDE_FETCH_MESSAGE }
// action/math.js
import { ADD, SQUARE, SET } from '../constants/ActionTypes'
import { startFetch, successFetch, failFetch, hideFetchMessage } from './fetch'
import axios from 'axios'
const uri = 'https://jsonplaceholder.typicode.com/posts/2'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }
export const setNum = () => (dispatch, getState) => {
  dispatch(startFetch)
  setTimeout(() => {
    dispatch(hideFetchMessage)
  }, 500)
  return axios
    .get(uri)
    .then(res => {
      setTimeout(() => {
        dispatch(successFetch)
        setTimeout(() => {
          dispatch(hideFetchMessage)
        }, 500)
        dispatch({ type: SET, num: res.data.id })
      }, 1000)
    })
    .catch(err => {
      dispatch(failFetch)
      setTimeout(() => {
        dispatch(hideFetchMessage)
      }, 500)
    })
}
// constants/ActionTypes.js
export const ADD = 'ADD'
export const SQUARE = 'SQUARE'
export const SET = 'SET'
export const SET_FETCH_MESSAGE = 'SET_FETCH_MESSAGE'
export const HIDE_FETCH_MESSAGE = 'HIDE_FETCH_MESSAGE'
// reduce/fetch.js
import { SET_FETCH_MESSAGE,HIDE_FETCH_MESSAGE } from '../constants/ActionTypes'
const initState = {
  message:'',
  isShow:false
}
const fetch = (state = initState, action) => {
  switch (action.type) {
    case SET_FETCH_MESSAGE:
      return {isShow: true, message: action.message}
    case HIDE_FETCH_MESSAGE:
      return { isShow: false, message: '' }
    default:
      return state
  }
}
export default fetch
// index.js
import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square, setNum } from './action/math'
const render = () => ReactDOM.render(
  <div store={store}>
    <p>{store.getState().math}</p>
    <input type="button" onClick={() => store.dispatch(setNum())} value="設置Num" />
    <input type="button" onClick={() => store.dispatch(add(1))} value="+1" />
    <input type="button" onClick={() => store.dispatch(add(2))} value="+2" />
    <input type="button" onClick={() => store.dispatch(square)} value="乘方" />
    {store.getState().fetch.isShow && <p>{store.getState().fetch.message}</p>}
  </div>,
  document.getElementById('root')
)
render()
store.subscribe(render)

  效果如下

  

展示和容器

  下麵來介紹react-redux。前面的代碼中,我們是通過store.subscribe()方法監控state狀態的變化來更新UI層的。而使用react-redux,可以讓組件動態訂閱狀態樹。狀態樹一旦被修改,組件能自動刷新顯示最新數據

  react-redux將所有組件分成兩大類:展示組件和容器組件。展示組件只負責UI呈現,所有數據由參數props提供;容器組件則負責管理數據和業務邏輯,帶有內部狀態,可使用redux的API。要使用react-redux,就要遵守它的組件拆分規範

【provider】

  react-redux提供Provider組件,可以讓容器組件預設可以拿到state,而不用當容器組件層級很深時,一級級將state傳下去

  將index.js文件更改如下

// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import store from './store'
import MathContainer from './container/MathContainer'
import { Provider } from 'react-redux'
ReactDOM.render(
  <Provider store={store}>
    <MathContainer />
  </Provider>,
  document.getElementById('root')
)

  按照組件拆分規範,將原來index.js中相關代碼,分拆到container/MathContainer和component/Math這兩個組件中

【connect】

  react-redux提供connect方法,用於從展示組件生成容器組件。connect的意思就是將這兩種組件連接起來

import { connect } from 'react-redux'
const MathContainer = connect()(Math);

  Math是展示組件,MathContainer就是由React-redux通過connect方法自動生成的容器組件

  為了定義業務邏輯,需要給出下麵兩方面的信息

  1、輸入邏輯:外部的數據(即state對象)如何轉換為展示組件的參數

  2、輸出邏輯:用戶發出的動作如何變為Action對象,從展示組件傳出去

  因此,connect方法的完整API如下

import {connect} from 'react-redux'
const MathContainer= connect(
    mapStateToProps,
    mapDispatchToProps
)(Math)

  上面代碼中,connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了展示組件的業務邏輯。前者負責輸入邏輯,即將state映射到UI組件的參數(props),後者負責輸出邏輯,即將用戶對展示組件的操作映射成Action

【mapStateToProps()】

  mapStateToProps建立一個從外部的state對象到展示組件的props對象的映射關係。作為參數,mapStateToProps執行後應該返回一個對象,裡面的每一個鍵值對就是一個映射。

const mapStateToProps = (state) => {
  return {
    num: getNum(state)                  
  }  
}

  mapStateToProps的第一個參數總是state對象,還可以使用第二個參數,代表容器組件的props對象。使用ownProps作為參數後,如果容器組件的參數發生變化,也會引發展示組件重新渲染

const mapStateToProps = (state,ownProps) => {
  return {
    num: getNum(state)                  
  }  
}

  mapStateToProps會訂閱Store,每當state更新的時候,就會自動執行,重新計算展示組件的參數,從而觸發展示組件的重新渲染。connect方法可以省略mapStateToProps參數,那樣,展示組件就不會訂閱Store,就是說Store的更新不會引起展示組件的更新

【mapDispatchToProps】

  mapDispatchToProps是connect函數的第二個參數,用來建立展示組件的參數到store.dispatch方法的映射。也就是說,它定義了用戶的哪些操作應該當作action,傳給Store。它可以是一個函數,也可以是一個對象

  如果mapDispatchToProps是一個函數,會得到dispatch和ownProps(容器組件的props對象)兩個參數

const mapDispatchToProps = (dispatch,ownProps) => {
  return {
    onSetNumClick: () => dispatch(setNum())
  }
}

  mapDispatchToProps作為函數,應該返回一個對象,該對象的每個鍵值對都是一個映射,定義了展示組件的參數怎樣發出action

  如果mapDispatchToProps是一個對象,它的每個鍵名也是對應展示組件的同名參數,鍵值應該是一個函數,會被當作action creator,返回的action會由redux自動發出

  因此,上面的寫法簡寫如下所示

const mapDispatchToProps = {
  onsetNumClick: () => setNum()
}

 

最終結構

  由於store目錄中,只能一個index.js文件,且不會有內容擴展,將其更改為根目錄下的store.js文件

  將其他的目錄都變成複數形式,最終的目錄結構如下所示

  效果如下

  詳細代碼如下所示,且可訪問github線上地址

【components】

// components/Math.js
import React from 'react'
const Math = ({
  num,
  isShow,
  fetchMessage,
  onSetNumClick,
  onAddOneClick,
  onAddTwoClick,
  onSqureClick
}) => (
  <section>
    <p>{num}</p>
    <input type="button" onClick={onSetNumClick} value="設置Num" />
    <input type="button" onClick={onAddOneClick} value="+1" />
    <input type="button" onClick={onAddTwoClick} value="+2" />
    <input type="button" onClick={onSqureClick} value="乘方" />
    {isShow && <p>{fetchMessage}</p>}
  </section>
)

export default Math

【containers】

// containers/MathContainer.js
import { connect } from 'react-redux'
import Math from '../components/Math'
import { getNum } from '../selectors/math'
import { getFetchMessage, getFetchIsShow } from '../selectors/fetch'
import { setNum, add, square } from '../actions/math'
const mapStateToProps = state => {
  return {
    num: getNum(state),
    fetchMessage: getFetchMessage(state),
    isShow: getFetchIsShow(state)
  }
}
const mapDispatchToProps = {
  onSetNumClick: () => setNum(),
  onAddOneClick: () => add(1),
  onAddTwoClick: () => add(2),
  onSqureClick: () => square
}
const MathContainer = connect(mapStateToProps, mapDispatchToProps)(Math)
export default MathContainer

【actions】

// actions/fetch.js
import { SET_FETCH_MESSAGE, HIDE_FETCH_MESSAGE } from '../constants/ActionTypes'
export const startFetch = { type: SET_FETCH_MESSAGE,message: '開始發送非同步請求' }
export const successFetch = { type: SET_FETCH_MESSAGE, message: '成功接收數據' }
export const failFetch = { type: SET_FETCH_MESSAGE, message: '接收數據失敗' }
export const hideFetchMessage = { type: HIDE_FETCH_MESSAGE }
// actions/math.js
import { ADD, SQUARE, SET } from '../constants/ActionTypes'
import { startFetch, successFetch, failFetch, hideFetchMessage } from './fetch'
import axios from 'axios'
const uri = 'https://jsonplaceholder.typicode.com/posts/2'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }
export const setNum = () => (dispatch, getState) => {
  dispatch(startFetch)
  setTimeout(() => {dispatch(hideFetchMessage)}, 300)
  return axios
    .get(uri)
    .then(res => {
      dispatch(successFetch)
      setTimeout(() => {dispatch(hideFetchMessage)}, 300)
      dispatch({ type: SET, num: res.data.id })
    })
    .catch(err => {
      dispatch(failFetch)
      setTimeout(() => {dispatch(hideFetchMessage)}, 300)
    })
}

【constants】

// constants/ActionTypes.js
export const ADD = 'ADD'
export const SQUARE = 'SQUARE'
export const SET = 'SET'
export const SET_FETCH_MESSAGE = 'SET_FETCH_MESSAGE'
export const HIDE_FETCH_MESSAGE = 'HIDE_FETCH_MESSAGE'

【reducers】

// reducers/fetch.js
import { SET_FETCH_MESSAGE,HIDE_FETCH_MESSAGE } from '../constants/ActionTypes'
const initState = {
  message:'',
  isShow:false
}
const fetch = (state = initState, action) => {
  switch (action.type) {
    case SET_FETCH_MESSAGE:
      return {isShow: true, message: action.message}
    case HIDE_FETCH_MESSAGE:
      return { isShow: false, message: '' }
    default:
      return state
  }
}
export default fetch
// reducers/index.js
import { combineReducers } from 'redux'
import math from './math'
import fetch from './fetch'
const rootReducer = combineReducers({
  math,
  fetch
})

export default rootReducer
// reduces/math.js
import { ADD, SQUARE,SET } from '../constants/ActionTypes'
const math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    case SET:
      return action.num
    default:
      return state
  }
}
export default math

【selectors】

// selectors/fetch.js
export const getFetchMessage = state => state.fetch.message
export const getFetchIsShow = state => state.fetch.isShow
//<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 加密需要 墨菲定律 安全機制 安全演算法 OpenSSL SSH ...
  • Linux 系統狀態的查看及管理工具: pstree ps pgrep&&pkill pidof top htop uptime vmstat iostat pmap glances dstat kill killall nohup screen systemd tmpfiles sleep chk ...
  • S5PV210 UART 相關說明 通用非同步收發器簡稱 UART, 即 UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER,它用來傳輸串列數據。發送數據時, CPU 將並行數據寫入 UART,UART 按照一定的格式在一根電線上串列發出;接收數據時, UA ...
  • 嵌入式開發中,大家免不了需要模擬調試代碼,線上調試是排除bug最有效直接的方式,今天我們要聊的是調試里最基礎的東西,即介面標準。ARM內核原生支持2種業界通用的介面標準,分別是JTAG和SWD。本節課豹哥先給大家詳細講講JTAG介面。 ...
  • 名詞解釋 clustered index(聚集索引) 對(primary key)主鍵索引的一種表述。InnoDB表存儲是基於primary key列來組織的,這樣做可以加快查詢和排序速度。為了獲得最好的性能,在選擇primary key columns的時候要特別小心。因為修改clustered ...
  • 一、問題如下 二、解決方法 重啟服務 右鍵我的電腦,選擇管理屬性,單擊進去 選擇服務目錄,查找MySQL項目,雙擊啟動。 ...
  • 一、SQL和PL/SQL的區別 SQL99是什麼(1)是操作所有關係型資料庫的規則(2)是第四代語言(3)是一種結構化查詢語言(4)只需發出合法合理的命令,就有對應的結果顯示SQL的特點(1)交互性強,非過程化(2)資料庫操縱能力強,只需發送命令,無需關註如何實現(3)多表操作時,自動導航簡單,例如 ...
  • 本文主要轉載自:ios開發 之 NSObject詳解 NSObject是大部分Objective-C類繼承體系的根類。這個類遵循NSObject協議,提供了一些通用的方法,對象通過繼承NSObject,可以從其中繼承訪問運行時的介面,並讓對象具備Objective-C對象的基本能力。下麵我們就詳細的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...