React-状态管理详解

1、传统MVC框架的缺陷

什么是MVC?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。

V即View视图是指用户看到并与之交互的界面。

M即Model模型是管理数据 ,很多业务逻辑都在模型中完成。在MVC的三个部件中,模型拥有最多的处理任务。

C即Controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

MVC只是看起来很美

MVC框架的数据流很理想,请求先到Controller, 由Controller调用Model中的数据交给View进行渲染,但是在实际的项目中,又是允许Model和View直接通信的。

2、Flux

在2013年,Facebook让React亮相的同时推出了Flux框架,React的初衷实际上是用来替代jQuery的,Flux实际上就可以用来替代Backbone.jsEmber.js等一系列MVC架构的前端JS框架。

其实FluxReact里的应用就类似于Vue中的Vuex的作用,但是在Vue中,Vue是完整的mvvm框架,而Vuex只是一个全局的插件。

React只是一个MVC中的V(视图层),只管页面中的渲染,一旦有数据管理的时候,React本身的能力就不足以支撑复杂组件结构的项目,在传统的MVC中,就需要用到Model和Controller。Facebook对于当时世面上的MVC框架并不满意,于是就有了Flux, 但Flux并不是一个MVC框架,他是一种新的思想。

在这里插入图片描述

  • View: 视图层
  • ActionCreator(动作创造者):视图层发出的消息(比如mouseClick)
  • Dispatcher(派发器):用来接收Actions、执行回调函数
  • Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面

Flux的流程:

  1. 组件获取到store中保存的数据挂载在自己的状态上
  2. 用户产生了操作,调用actions的方法
  3. actions接收到了用户的操作,进行一系列的逻辑代码、异步操作
  4. 然后actions会创建出对应的action,action带有标识性的属性
  5. actions调用dispatcher的dispatch方法将action传递给dispatcher
  6. dispatcher接收到action并根据标识信息判断之后,调用store的更改数据的方法
  7. store的方法被调用后,更改状态,并触发自己的某一个事件
  8. store更改状态后事件被触发,该事件的处理程序会通知view去获取最新的数据

3、Redux

React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。

  • 代码结构
  • 组件之间的通信

2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。

如果你不知道是否需要 Redux,那就是不需要它

只有遇到 React 实在解决不了的问题,你才需要 Redux

简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

  • 用户的使用方式非常简单
  • 用户之间没有协作
  • 不需要与服务器大量交互,也没有使用 WebSocket
  • 视图层(View)只从单一来源获取数据

需要使用Redux的项目:

  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了WebSocket
  • View要从多个来源获取数据

从组件层面考虑,什么样子的需要Redux:

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

Redux的设计思想:

  1. Web 应用是一个状态机,视图与状态是一一对应的。
  2. 所有的状态,保存在一个对象里面(唯一数据源)。

注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。

Redux的使用的三大原则:

  • Single Source of Truth(唯一的数据源)
  • State is read-only(状态是只读的)
  • Changes are made with pure function(数据的改变必须通过纯函数完成)

(1) 自己实现Redux - 不讲解

这个部分,不使用react,直接使用原生的html/js来写一个简易的的redux

基本的状态管理及数据渲染:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Redux principle 01</title>
</head>
<body><h1>redux principle</h1><div class="counter"><span class="btn" onclick="dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span><span class="count" id="count"></span><span class="btn" id="add" onclick="dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span></div><script>// 定义一个计数器的状态const countState = {count: 10}// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态const changeState = (action) => {switch(action.type) {// 处理减case 'COUNT_DECREMENT':countState.count -= action.numberbreak;// 处理加        case 'COUNT_INCREMENT':countState.count += action.numberbreak;default:break;}}// 定义一个方法用于渲染计数器的domconst renderCount = (state) => {const countDom = document.querySelector('#count')countDom.innerHTML = state.count}// 首次渲染数据renderCount(countState)// 定义一个dispatch的方法,接收到动作之后,自动调用const dispatch = (action) => {changeState(action)renderCount(countState)}</script>
</body>
</html>

创建createStore方法

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Redux principle 02</title>
</head>
<body><h1>redux principle</h1><div class="counter"><span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span><span class="count" id="count"></span><span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span></div><script>// 定义一个方法,用于集中管理state和dispatchconst createStore = (state, changeState) => {// getState用于获取状态const getState = () => state// 定义一个监听器,用于管理一些方法const listeners = []const subscribe = (listener) => listeners.push(listener)// 定义一个dispatch方法,让每次有action传入的时候返回render执行之后的结果const dispatch = (action) => {// 调用changeState来处理数据changeState(state, action)// 让监听器里的所以方法运行listeners.forEach(listener => listener())}return {getState,dispatch,subscribe}}// 定义一个计数器的状态const countState = {count: 10}// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态const changeState = (state, action) => {switch(action.type) {// 处理减case 'COUNT_DECREMENT':state.count -= action.numberbreak;// 处理加        case 'COUNT_INCREMENT':state.count += action.numberbreak;default:break;}}// 创建一个storeconst store = createStore(countState, changeState)// 定义一个方法用于渲染计数器的domconst renderCount = () => {const countDom = document.querySelector('#count')countDom.innerHTML = store.getState().count}// 初次渲染数据renderCount()// 监听,只要有dispatch,这个方法就会自动运行store.subscribe(renderCount)</script>
</body>
</html>

让changeState方法变为一个纯函数

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Redux principle 03</title>
</head>
<body><h1>redux principle</h1><div class="counter"><span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span><span class="count" id="count"></span><span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span></div><script>// 定义一个方法,用于集中管理state和dispatchconst createStore = (state, changeState) => {// getState用于获取状态const getState = () => state// 定义一个监听器,用于管理一些方法const listeners = []const subscribe = (listener) => listeners.push(listener)// 定义一个dispatch方法,让每次有action传入的时候返回render执行之后的结果const dispatch = (action) => {// 调用changeState来处理数据state = changeState(state, action)// 让监听器里的所有方法运行listeners.forEach(listener => listener())}return {getState,dispatch,subscribe}}// 定义一个计数器的状态const countState = {count: 10}// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态const changeState = (state, action) => {switch(action.type) {// 处理减case 'COUNT_DECREMENT':return {...state,count: state.count - action.number}// 处理加        case 'COUNT_INCREMENT':return {...state,count: state.count + action.number}default:return state}}// 创建一个storeconst store = createStore(countState, changeState)// 定义一个方法用于渲染计数器的domconst renderCount = () => {const countDom = document.querySelector('#count')countDom.innerHTML = store.getState().count}// 初次渲染数据renderCount()// 监听,只要有dispatch,这个方法就会自动运行store.subscribe(renderCount)</script>
</body>
</html>

合并state和changeState(最终版)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Redux principle 04</title>
</head>
<body><h1>redux principle</h1><div class="counter"><span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span><span class="count" id="count"></span><span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span></div><script>// 定义一个方法,用于集中管理state和dispatch, changeState改名了,专业的叫法是reducerconst createStore = (reducer) => {// 定义一个初始的statelet state = null// getState用于获取状态const getState = () => state// 定义一个监听器,用于管理一些方法const listeners = []const subscribe = (listener) => listeners.push(listener)// 定义一个dispatch方法,让每次有action传入的时候返回reducer执行之后的结果const dispatch = (action) => {// 调用reducer来处理数据state = reducer(state, action)// 让监听器里的所有方法运行listeners.forEach(listener => listener())}//  初始化statedispatch({})return {getState,dispatch,subscribe}}// 定义一个计数器的状态const countState = {count: 10}// 定一个方法叫changeState,用于处理state的数据,每次都返回一个新的状态const changeState = (state, action) => {// 如果state是null, 就返回countStateif (!state) return countStateswitch(action.type) {// 处理减case 'COUNT_DECREMENT':return {...state,count: state.count - action.number}// 处理加        case 'COUNT_INCREMENT':return {...state,count: state.count + action.number}default:return state}}// 创建一个storeconst store = createStore(changeState)// 定义一个方法用于渲染计数器的domconst renderCount = () => {const countDom = document.querySelector('#count')countDom.innerHTML = store.getState().count}// 初次渲染数据renderCount()// 监听,只要有dispatch,renderCount就会自动运行store.subscribe(renderCount)</script>
</body>
</html>

(2) 使用Redux框架

Redux的流程:

在这里插入图片描述

  • store通过reducer创建了初始状态

  • view通过store.getState()获取到了store中保存的state挂载在了自己的状态上

  • 用户产生了操作,调用了actions 的方法

  • actions的方法被调用,创建了带有标示性信息的action

  • actions将action通过调用store.dispatch方法发送到了reducer中

  • reducer接收到action并根据标识信息判断之后返回了新的state

  • store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state

Reducer必须是一个纯函数:

Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。Reducer不是只有Redux里才有,之前学的数组方法reduce, 它的第一个参数就是一个reducer

纯函数是函数式编程的概念,必须遵守以下一些约束。

  • 不得改写参数

  • 不能调用系统 I/O 的API

  • 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果

由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。

// State 是一个对象
function reducer(state = defaultState, action) {return Object.assign({}, state, { thingToChange });// 或者return { ...state, ...newState };
}// State 是一个数组
function reducer(state = defaultState, action) {return [...state, newItem];
}

最好把 State 对象设成只读。要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变(immutable)的对象。

我们可以通过在createStore中传入第二个参数来设置默认的state,但是这种形式只适合于只有一个reducer的时候。

  • 定义状态管理器
// src/store/index.js
// cnpm i redux -S
// 引入创建store的函数
import { createStore } from 'redux'// const reducer = () => {}
// const reducer = ( state, action) => {}
// const reducer = ( state = { a: 1, b: 2}, action) => {}
// const reducer = ( state = { a: 1, b: 2}, { type, payload }) => {}// 创建纯函数 - 设定初始化的值,修改状态
// 纯函数 : 输入一定,输出一定确定
// 纯函数中不写 Date.now() / Math.random()
// 第一个参数代表 状态管理器中 的 初始化的状态 ,可以是常用的任何数据类型
// 第二个参数 代表 用户操作的对应的行为以及传递的参数
const reducer = (state = {username: '',list: []
}, action) => {// type 代表用户的某个行为// payload 代表的传递的参数const { type, payload } = action// 改变状态switch (type) {case 'CHANGE_USERNAME':// 因为状态是只读的,需要处理,必须返回一个全新的对象// Object.assign()是 ES6 新增的 --- 拷贝对象return Object.assign({}, state, { username: payload })case 'CHANGE_LIST':// 扩展运算符合并对象  --- 拷贝对象return { ...state, list: payload }default:return state}
}
// 创建状态管理器
const store = createStore(reducer)export default store
  • 入口文件处订阅数据的变化
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'import store from './07store/index'
function render () {ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,document.querySelector('#root'))
}
render()
console.log(store)
// dispatch   -----   组件触发 action
// getState   -----   获取组件的状态
// subscribe  -----   订阅状态管理器的变化
store.subscribe(render) // 如果状态管理器发生数据改变,执行render函数
  • 组件使用状态管理器
import React, { Component } from 'react'
import store from './07store/index'
export default class App extends Component {addFn () {const arr = store.getState().listarr.push(store.getState().username)store.dispatch({type: 'CHANGE_LIST',payload: arr})}deleteFn (index) {const arr = store.getState().listarr.splice(index, 1)store.dispatch({type: 'CHANGE_LIST',payload: arr})}render() {console.log(store.getState())const { username, list } = store.getState()return (<div><input type="text" value={ username } onChange = {(e) => {// 修改状态store.dispatch({type: 'CHANGE_USERNAME',payload: e.target.value})}}/><button onClick = { this.addFn.bind(this) }>添加</button><ul>{list && list.map((item, index) => {return (<li key = { index }>{ item }<button onClick = { () => {this.deleteFn(index)}}>X</button></li>)})}</ul></div>)}
}

划分reducer:

因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起

注意:

  1. 分离reducer的时候,每一个reducer维护的状态都应该不同
  2. 通过store.getState获取到的数据也是会按照reducers去划分的
  3. 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态

最开始一般基于计数器的例子讲解redux的基本使用即可

关于action/reducer/store的更多概念,请查看官网

Redux异步

通常情况下,action只是一个对象,不能包含异步操作,这导致了很多创建action的逻辑只能写在组件中,代码量较多也不便于复用,同时对该部分代码测试的时候也比较困难,组件的业务逻辑也不清晰,使用中间件了之后,可以通过actionCreator异步编写action,这样代码就会拆分到actionCreator中,可维护性大大提高,可以方便于测试、复用,同时actionCreator还集成了异步操作中不同的action派发机制,减少编码过程中的代码量

常见的异步库:

  • Redux-thunk
  • Redux-saga
  • Redux-effects
  • Redux-side-effects
  • Redux-loop
  • Redux-observable

基于Promise的异步库:

  • Redux-promise
  • Redux-promises
  • Redux-simple-promise
  • Redux-promise-middleware

(3) 容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)

展示组件容器组件
作用描述如何展现(骨架、样式)描述如何运行(数据获取、状态更新)
直接使用 Redux
数据来源props监听 Redux state
数据修改从 props 调用回调函数向 Redux 派发 actions
调用方式手动通常由 React Redux 生成

(4) 使用react-redux

可以先结合context来手动连接react和redux。

react-redux提供两个核心的api:

  • Provider: 提供store

  • connect: 用于连接容器组件和展示组件

    • Provider

      根据单一store原则 ,一般只会出现在整个应用程序的最顶层。

    • connect

      语法格式为

      connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(component)

      一般来说只会用到前面两个,它的作用是:

      • store.getState()的状态转化为展示组件的props
      • actionCreators转化为展示组件props上的方法

特别强调:

官网上的第二个参数为mapDispatchToProps, 实际上就是actionCreators

只要上层中有Provider组件并且提供了store, 那么,子孙级别的任何组件,要想使用store里的状态,都可以通过connect方法进行连接。如果只是想连接actionCreators,可以第一个参数传递为null

  • 创建状态管理器
// src/store/index.js
import { createStore } from 'redux'const reducer = (state = {proList: [],skillList: []
}, { type, payload }) => {switch (type) {case 'CHANGE_PRO_LIST':return { ...state, proList: payload }case 'CHANGE_SKILL_LIST':return { ...state, skillList: payload }default:return state}
}const store = createStore(reducer)export default store
  • 处理入口文件
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App.jsx'
import store from './store'ReactDOM.render(<React.StrictMode><Provider store = { store }><App /></Provider></React.StrictMode>,document.querySelector('#root')
)
  • 组件使用
import React, { Component } from 'react'
import { connect } from 'react-redux'
class App extends Component {componentDidMount () {this.props.getProListData()this.props.getSkillListData()}render() {const { proList, skillList } = this.propsreturn (<div><h1>秒杀列表</h1><ul>{skillList && skillList.map(item => {return (<li key = { item.proid }>{ item.proname }</li>)})}</ul><h1>产品列表</h1><ul>{proList && proList.map(item => {return (<li key = { item.proid }>{ item.proname }</li>)})}</ul></div>)}
}
// const mapStateToProps = state => {
//   return {
//     proList: state.proList,
//     skillList: state.skillList
//   }
// }
const mapStateToProps = ({ proList, skillList }) => ({ proList, skillList })const mapDispatchToProps = (dispatch) => {return {getProListData () {fetch('http://121.89.205.189/api/pro/list').then(res => res.json()).then(res => {dispatch({type: 'CHANGE_PRO_LIST',payload: res.data})})},getSkillListData () {fetch('http://121.89.205.189/api/pro/seckilllist').then(res => res.json()).then(res => {dispatch({type: 'CHANGE_SKILL_LIST',payload: res.data})})}}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)

分reducer / 异步处理action

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62878.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PH热榜 | 2024-12-02

1. Muku.ai 标语&#xff1a;AI网红广告代理公司 介绍&#xff1a;木库AI是家AI网红营销机构&#xff0c;利用AI虚拟形象创作用户原创视频广告。只需提供产品链接&#xff0c;就能生成吸引人的内容&#xff0c;从而提升各大平台的销售额。 产品网站&#xff1a; 立即访问 P…

Flink学习连载文章9--状态(State)

State state 可以理解为-- 历史计算结果 有状态计算和无状态计算 无状态计算: 不需要考虑历史数据, 相同的输入,得到相同的输出!如:map, 将每个单词记为1, 进来一个hello, 得到(hello,1),再进来一个hello,得到的还是(hello,1) 有状态计算: 需要考虑历史数据, 相同的输入,可…

嵌入式硬件面试题【经验】总结----会不断添加更新

目录 引言 一、电阻 1、电阻选型时一般从那几个方面考虑 2、上拉电阻的作用 3、PTC热敏电阻作为电源电路保险丝的工作原理 4、如果阻抗不匹配&#xff0c;有哪些后果 二、电容 1、电容选型一般从哪些方面进行考虑? 2、1uf的电容通常来滤除什么频率的信号 三、三极管…

Linux——基础命令(2) 文件内容操作

目录 ​编辑 文件内容操作 1.Vim &#xff08;1&#xff09;移动光标 &#xff08;2&#xff09;复制 &#xff08;3&#xff09;剪切 &#xff08;4&#xff09;删除 &#xff08;5&#xff09;粘贴 &#xff08;6&#xff09;替换,撤销,查找 &#xff08;7&#xff…

Stable Diffusion 3详解

&#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&…

微信小程序——文档下载功能分享(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

开源的跨平台SQL 编辑器Beekeeper Studio

一款开源的跨平台 SQL 编辑器&#xff0c;提供 SQL 语法高亮、自动补全、数据表内容筛选与过滤、连接 Web 数据库、存储历史查询记录等功能。该编辑器支持 SQLite、MySQL、MariaDB、Postgres 等主流数据库&#xff0c;并兼容 Windows、macOS、Linux 等桌面操作系统。 项目地址…

Shader的涉及的数学知识总结

着色器&#xff08;Shader&#xff09;编程广泛应用于计算机图形学中&#xff0c;用于实现各种视觉效果。编写高效的着色器需要扎实的数学基础&#xff0c;以下是着色器编程中常见的数学知识及其应用&#xff1a; 1. 向量代数 向量&#xff1a;表示具有大小和方向的量&#x…

数据结构——排序第三幕(深究快排(非递归实现)、快排的优化、内省排序,排序总结)超详细!!!!

文章目录 前言一、非递归实现快排二、快排的优化版本三、内省排序四、排序算法复杂度以及稳定性的分析总结 前言 继上一篇博客基于递归的方式学习了快速排序和归并排序 今天我们来深究快速排序&#xff0c;使用栈的数据结构非递归实现快排&#xff0c;优化快排&#xff08;三路…

Spring Web开发注解和请求(1)

大家好我是小帅&#xff0c;今天我们来学习Spring Web MVC框架&#xff08;入门级&#xff09; 文章目录 1. 什么是 Spring Web MVC&#xff1f;1.1 MVC 定义1.2 什么是Spring MVC ? 2. 学习Spring MVC2.1 建⽴连接第一个spring MVC程序 3. web开发注解的解释3.1RestControlle…

剖析kubernetes service的IP能否在宿主机中ping通

文章目录 前言一、serviceIP是怎么产生的二、宿主机中ping serviceIP地址1.ping示例2.为什么ping不通剖析2.1.封装及解封装过程2.2.ICMP报文以太网数据帧格式2.3.原因 三、ping不通svcIP是否跟iptables规则有关&#xff1f;四、为什么ipvs的的clusterIP类型的service能够ping通…

vue项目部署到github pages后页面显示不出来??

问题&#xff1a; 当我们在命令行执行 npm run build 后&#xff0c;项目的目录下会生成一个 dist 文件夹&#xff0c;它里面又包含一个 static 文件夹和一个 index.html 文件&#xff0c;这是 webpack 最终打包好的文件 项目上传到仓库后发现页面为空&#xff0c;找不到文件路…

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本)

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) code review! 参考笔记 1.ROS基本框架1——编写简单的发布者和订阅者(C++和Python版本) 2.ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) 文章目录 ROS基本框架2——在ROS开发中创建并使用自定义…

ccf A 类与sci 一区那个比较难? + 论文常识

论文常识&#xff1a; ESI 基本科学指标数据库(EssentialScience Indicators ) 高被引论文&#xff08;Highly Cited Paper&#xff09;&#xff1a;根据同一年同一ESI学科统计最近10年发表论文中被引用次数进入世界前1%的论文&#xff1b;在硕士论文中文献综述是作为论文的理…

异步处理优化:多线程线程池与消息队列的选择与应用

目录 一、异步处理方式引入 &#xff08;一&#xff09;异步业务识别 &#xff08;二&#xff09;明确异步处理方式 二、多线程线程池&#xff08;Thread Pool&#xff09; &#xff08;一&#xff09;工作原理 &#xff08;二&#xff09;直面优缺点和适用场景 1.需要快…

IS-IS的原理

IS-IS的基本概念&#xff1a; 概述&#xff1a; IS-IS&#xff0c;中间系统到中间系统&#xff0c;是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络&#xff0c;采用数据链路层封装&#xff0c;区别于ospf只支持IP网络&#xff0…

代理ip工具在网络安全中的作用是什么

代理IP工具在网络安全中扮演着至关重要的角色&#xff0c;它们不仅能够帮助用户保护隐私&#xff0c;还能提高网络性能&#xff0c;增强安全性。本文将深入探讨代理IP工具的定义、工作原理以及在网络安全中的具体应用&#xff0c;旨在为读者提供全面的理解和指导。 一、代理IP工…

IDEA 2024 配置Maven

Step 1:确定下载Apache Maven版本 在IDEA 2024中&#xff0c;随便新建一个Maven项目&#xff1b; 在File下拉菜单栏中&#xff0c;找到Setings&#xff1b; 在Build&#xff0c;Execution&#xff0c;Deployment中找到Maven 确定下载的Apache Maven版本应略低于或等于IDEA绑…

107.【C语言】数据结构之二叉树求总节点和第K层节点的个数

目录 1.求二叉树总的节点的个数 1.容易想到的方法 代码 缺陷 思考:能否在TreeSize函数内定义静态变量解决size的问题呢? 其他写法 运行结果 2.最好的方法:分而治之 代码 运行结果 2.求二叉树第K层节点的个数 错误代码 运行结果 修正 运行结果 其他写法 1.求二…

MySQL笔记-启动时log报错Table ‘mysql.user‘ doesn‘t exist

安装好mysql后&#xff0c;正常使用&#xff08;使用的是rpm版安装的&#xff09; service mysqld start | stop | restart 不会出现这个问题。 我遇到的情况是在凝思操作系统上&#xff0c;已经存在了一个mysql。网上查找了一些资料&#xff0c;卸载&#xff0c;后可能卸载…