后端程序员入门react笔记(八)-redux的使用和项目搭建

一个更好用的文档

添加链接描述

箭头函数的简化

//简化前
function countIncreAction(data) {return {type:"INCREMENT",data}
}
//简化后
const countIncreAction =data=>({type:"INCREMENT",data
})

react UI组件库相关资料

组件库连接和推荐
antd组件库文档
Material UI

举例

import React, {Component} from 'react';
import { Button, DatePicker } from 'antd';class App extends Component {render() {return (// 注意此处要用BrowserRouter包括根组件,可以提到index.js里面包裹App标签<div><ul><Button type="primary">PRESS ME</Button><DatePicker placeholder="select date" /></ul></div>);}
}
export default App;

export和export default区别

  • export 和 export default 都是es6语法中用来导出组件的
  • 可以导出的文档类型有( 数据、常量、函数、js文件、模块等)

区别

  • 一个文件中如果有多个模块需要export,则使用export
export  class Com extends Component{render() {return (<div ><h1>这是头部</h1></div>)}
}export const str = '我是要被导出的str'// import 引入方式  
import { Com , str } // 引入时需要解构出来 可以解构多个 用 , 号隔开 
  • export default 看名字就知道了,一个文件中只有一个模块被声明
function  fn (){console.log('我是fn函数')
}export default fn //exprot default  导出时不会去关注 文件内容  只要名称对应即可//export 必须写在 文件最后;// 引入方式
import fn from '../'

redux

  • redux是一个专门用于做状态怪的js库
  • 可以用在vue、react、angular项目中,但基本与react配合使用
  • 作用:集中式管理react应用中的多个组件共享的状态,可以把组件内需要共享的状态交给redux管理

应用场景

  • 状态共享:某个组件的状态,需要让其他组件可以随时拿到(共享)
  • 组件通信:一个组件需要改变另一个组件的状态(通信)
  • 总体原则:能不用就不用,如果不用比较吃力才用

流程图

我们先来看一下redux的工作流程,可以有一个大概的印象,我们看到,redux的核心有三个,一个是action creator, 一个是store,一个是reducers,其中redux的核心是什么?是store,我们调用redux,其实就是调用store的api,那么store负责api,谁负责干活呢?reducer,真正负责处理逻辑是在reducer里面。react component 我们自己的组件,负责和store交互
在这里插入图片描述

我们可以先来看一个简单的列子

  • store的实现,其实store是不用我们实现的,我们只需要引入redux包,create一个store就可以了。
//引入store
import {createStore} from "redux"
import {countReducer} from "./count_reducer"
//引入reducer
export default createStore(countReducer)
  • store负责和组件交互,但是需要依赖注入,即store要把任务交给谁处理,真正处理的这个人,就是reducer,所以我们写一个reducer的逻辑,reducer就是一个纯function,接收两个参数,一个是基础数据,一个是操作方式。
export function countReducer(state = 1, action) {const {type,data}=actionconsole.log(state,action);switch (type) {case 'INCREMENT'://注意,这个return的值就是statereturn state + data*1;case 'DECREMENT':return state - data*1;default:return state;}
}
  • 至此 store和reducer我们都编辑完毕了,但是我们在组建中怎么调用呢?我们接下来编写组件
import React, {Component, createRef} from 'react';
import store from "../../redux/store"class Count extends Component {sel=createRef();increment=()=>{const {value}=this.sel.current//store去分发任务store.dispatch({type: "INCREMENT",data:value})}decrement=()=>{const {value}=this.sel.current//store去分发任务store.dispatch({type: "DECREMENT",data:value})}incrementOdd=()=>{const {value}=this.sel.currentconst oldVal=store.getState()//store去分发任务if(oldVal%2===0){return}store.dispatch({type: "INCREMENT",data:value})}incrementAsync=()=>{const {value}=this.sel.currentsetTimeout(()=>{//store去分发任务store.dispatch({type: "INCREMENT",data:value})},1000)}render() {return (<div>{/*store.getState() 后去state的值*/}<h1>当前求和为:{store.getState()}</h1><select name="" id="" ref={this.sel}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button onClick={this.increment}>+</button><button onClick={this.decrement}>-</button><button onClick={this.incrementOdd}>奇数加</button><button onClick={this.incrementAsync}>异步加</button></div>);}
}export default Count;
  • 我们通过store.dispatch去分发任务,修改了state,但是redux有一个问题,他只负责存储和更新state,但是不负责调render,这就导致我们的state变化之后页面不能刷新,所以,我们还得调用一下setstate接口来更新render,那么另一个问题又来了,什么时候去setstate呢?我们需要redux告知我们,这个api就是store.subscribe,所以我们在index.js就给监听上
import React from 'react';
import ReactDOM from "react-dom/client";
import App from "./App";
import store from "./redux/store"
// ReactDOM.createRoot(document.getElementById("root")).render(app)
const root=ReactDOM.createRoot(document.getElementById("root"))
root.render(<App />)//注意App标签一定不要预先定义,否则会编译为静态标签而导致无法更新
store.subscribe(()=>{root.render(<App />)
})
  • 自此,一个简单的redux功能实现了。

redux demo实例

  • 前面我们用了store和reducer,但是action是什么我并未涉及,接下来我们看怎么创建一个action文件count_action.js
const countIncreAction =data=>({type:"INCREMENT",data
})const countdecreAction = (data) => ({type: "DECREMENT",data
})
  • 诶,我们发现一个现象,这个写法和我们使用store分发任务有点像
    decrement=()=>{const {value}=this.sel.current//store去分发任务store.dispatch({type: "DECREMENT",data:value})}
  • 那我们怎么把我们自己写的换成action呢,我们来替换一下,我们先引入,再替换
import React, {Component, createRef} from 'react';
import store from "../../redux/store"
import {countIncreAction,countdecreAction} from "../../redux/count_action"class Count extends Component {sel=createRef();increment=()=>{const {value}=this.sel.current//store去分发任务store.dispatch(countIncreAction(value))}
}export default Count;
  • 关于一些优化,我们知道,在代码中,如果能用常量或者变量代替字符串,那么就用变量或者常量在代码中使用,那么我们可以使用一个常量文件来管理这些

异步action

action 可以返回一个对象,交由store去用,但是如果是我们想要一个异步的action怎么办呢?我们的对象里面也不支持自定义时间啊。redux很明显不支持,但是有一个组件提供了这种功能,就是redux-thunk,它通过store可以接收第二个参数,以applyMiddleware的形式让store可以接收function。我们来看一下,首先我们创建一个可以接收function的store

//引入store
import {applyMiddleware, createStore} from "redux"
import {countReducer} from "./count_reducer"
import {thunk} from "redux-thunk"
//引入reducer
export default createStore(countReducer,applyMiddleware(thunk))
  • 那么我们在使用的时候就可以简单这样使用
    incrementAsync=()=>{const {value}=this.sel.currentstore.dispatch(countIncreAsyncAction(value,1000))}

react-redux

react-redux是由官方出的一个组件库,用来简化对redux的操作。redux对组件做了区分,一种是UI组件,负责页面展示,一种是容器组件负责逻辑处理,既然是这样,那么和redux能交互的就只有容器组件(container),容器组件拿到数据后通过props传递给UI组件(component)
在这里插入图片描述
我们把count.jsx改成纯UI组件,如下

import React, {Component, createRef} from 'react';
class CountUI extends Component {sel=createRef();increment=()=>{const {value}=this.sel.current}decrement=()=>{const {value}=this.sel.current}incrementOdd=()=>{const {value}=this.sel.current}incrementAsync=()=>{const {value}=this.sel.current}render() {return (<div><h1>当前求和为:0</h1><select name="" id="" ref={this.sel}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button onClick={this.increment}>+</button><button onClick={this.decrement}>-</button><button onClick={this.incrementOdd}>奇数加</button><button onClick={this.incrementAsync}>异步加</button></div>);}
}
export default CountUI;
  • 我们创建一个container组件
//这个文件就是容器组件,负责和redux交互并传递数据给UI组件
//引入UI组件
import {CountUI} from "../../components/count/count"
import {connect} from "react-redux"
//创建一个
//创建一个容器组件并暴露
export default connect()(CountUI)
  • 我们说过,容器不仅要传递数据给UI组件,还需要和redux交互呢,和redux交互其实就是调用store的接口,那么我们怎么和store联系上呢?我们在App里面改一下。
    render() {return (<div><Count store={store} /></div>);}
}

connect

具体来说,connect接收两个参数,

  • 一个是mapStateToProps,默认传入state参数,也就是讲state数据以props的形式传递给子组件
  • 一个是mapDispathcToProps ,默认传入一个dispatch参数,用来指定分发任务给哪个action,接下来我们看一下这redux,component,container的交互
//这个文件就是容器组件,负责和redux交互并传递数据给UI组件
//引入UI组件
import {CountUI} from "../../components/count/count"
import {connect} from "react-redux"
import {countDecreAction, countIncreAction, countIncreAsyncAction} from "../../redux/count_action"
//在此指定数据,即把那些state赋值给props
function mapStateToProps(state) {return {count: state}
}
//在此指定redux,即让哪个redux来处理数据
function mapDispathcToProps(dispatch) {return {add: (data) =>dispatch(countIncreAction(data)),addOdd: (data) =>dispatch(countIncreAction(data)),addAsync: (data) =>dispatch(countIncreAsyncAction(data,1000)),sub: (data) => dispatch(countDecreAction(data))}
}
//创建一个容器组件并暴露
//参数解释:mapStateToProps用来传递数据  mapDispathcToProps用来指定redux ,返回一个函数后,然后指定要绑定哪个UI组件
export default connect(mapStateToProps, mapDispathcToProps)(CountUI)
  • 容器组件写好之后,我们在UI组件怎么调用呢,很简单,从props获取即可
import React, {Component, createRef} from 'react';
export class CountUI extends Component {sel=createRef();increment=()=>{const {value}=this.sel.currentthis.props.add(value)}decrement=()=>{const {value}=this.sel.currentthis.props.sub(value)}incrementOdd=()=>{const oldValue=this.props.countconst {value}=this.sel.currentif (oldValue%2===0){return}this.props.addOdd(value)}incrementAsync=()=>{const {value}=this.sel.currentthis.props.addAsync(value)}render() {return (<div><h1>当前求和为:{this.props.count}</h1><select name="" id="" ref={this.sel}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button onClick={this.increment}>+</button><button onClick={this.decrement}>-</button><button onClick={this.incrementOdd}>奇数加</button><button onClick={this.incrementAsync}>异步加</button></div>);}
}
  • 简化版
//这个文件就是容器组件,负责和redux交互并传递数据给UI组件
//引入UI组件
import {CountUI} from "../../components/count/count"
import {connect} from "react-redux"
import {countDecreAction, countIncreAction, countIncreAsyncAction} from "../../redux/count_action"
export default connect(state => ({count: state}),{add: countIncreAction,addOdd: countIncreAction,addAsync: countIncreAsyncAction,sub: countDecreAction}
)(CountUI)

react-redux的优化

  • 既然react-redux 是对redux进行了优化,那么react-redux会不会在state发生变化的时候来实现自动render呢?答案是肯定的,我们来试一下
import React from 'react';
import ReactDOM from "react-dom/client";
import App from "./App";
import store from "./redux/store"
// ReactDOM.createRoot(document.getElementById("root")).render(app)
const root=ReactDOM.createRoot(document.getElementById("root"))
root.render(<App />)
// 使用react-redux 注释掉监听store
// store.subscribe(()=>{
//     root.render(<App />)
// })
  • provider

我们知道,每个容器组件我们都需要传递一个store,像这样

<Count1 store={store} />
<Count2 store={store} />
<Count3 store={store} />

这样看起来明显是不科学的,那么有没有一种方法,让我们写一次,就可以不用写了呢,有,首先第一点我想到的就是用一个特殊标签包裹一下这些组件,只要在标签内的,都默认传递了store,react真的这么做了,这饿就是provider ,我们来看一下怎么用

import React from 'react';  
import ReactDOM from "react-dom/client";  
import App from "./App";  
import {Provider} from "react-redux"  
import store from "./redux/store"  
const root=ReactDOM.createRoot(document.getElementById("root"))  
root.render(<Provider store={store}><App /></Provider>)
  • 我们还可以把UI组件整合到container里面去,组成一个文件

image.png

多组件数据共享

  • 我们先来创建这样一个项目目录,在src目录下,来实现数据共享

image.png

  • 我们先从最简单的来,先来定义action文件

a-action.js

export const AAction = data=>({data:data,type:'AAction'})

b-action.js

export const BAction = data=>({data:data,type:'BAction'})
  • 再来编写reducer

a-reducer.js

const initUser=[{id:1,name:'小a',age:18}]  
export const aReducer = (state = initUser, action) => {  
const {type, data} = action  
switch (action.type) {  
case 'AAction':  
return [data,...state]  
default:  
return state
}  
}

b-reducer.js

const initUser=[{id:1,name:'小b',age:118}]  
export const bReducer = (state = initUser, action) => {  
const {type, data} = action  
switch (action.type) {  
case 'BAction':  
return [data,...state]  
default:  
return state
}  
}
  • action reducer都有了,我们开始写store,我们知道创建store的这行代码export default createStore(countReducer,applyMiddleware(thunk)),里面的参数接收的是一个reducer,那么如果我有多个reducer怎么办呢?我们就用到了combineReducers
//引入store  
import {combineReducers, createStore} from "redux"  
//引入reducer  import {aReducer} from "./reducers/a-reducer"  
import {bReducer} from "./reducers/b-reducer"  
//将多个reducer写入一个对象 注意是key=>value 格式书写  
const rootReducer = combineReducers({  
"areducer":aReducer,  
"breducer":bReducer  
})  
export default createStore(rootReducer)
  • 我们在index.js中引入store,使用provider支持对容器的store传递
import React from 'react';  
import ReactDOM from "react-dom/client";  
import App from "./App";  
import {Provider} from "react-redux"  
import store from "./redux/store"  
const root=ReactDOM.createRoot(document.getElementById("root"))  
root.render(<Provider store={store}><App /></Provider>)
  • 在a容器组件中暴露connect
import React, {Component, createRef} from 'react';  
import {nanoid} from "nanoid";  
import {AAction} from "../../redux/actions/a-action";  
import {connect} from "react-redux";  class AUI extends Component {  nameRef=createRef();  
ageRef=createRef();  addUser=()=>{  
let id=nanoid();  
let name=this.nameRef.current.value;  
let age=this.ageRef.current.value;  
this.props.addAUser({id,name,age});  
}  
render() {  
// console.log(this.props);  
const {auser,buser}=this.props  
return (  
<div>  
<h2>我是a组件</h2>  
<input type="text" ref={this.nameRef} placeholder="name"/>  
<input type="text" ref={this.ageRef} placeholder="age"/>  
<button onClick={this.addUser}>添加用户</button>  
<h4>a组件用户</h4>  
<ul>  
{auser.map((item=><li key={item.id}>name: {item.name} | age: {item.age}</li>))}  
</ul>  
<h4>b组件用户</h4>  
<ul>  
{buser.map((item=><li key={item.id}>name: {item.name} | age: {item.age}</li>))}  
</ul>  
</div>  
);  
}  
}  
//注意,取state的时候要根据前面定义的key来取  
export default connect(state=>({auser:state.areducer,buser:state.breducer}),{addAUser:AAction})(AUI);
  • 在b容器组件中暴露connect
import React, {Component, createRef} from 'react';  
import {nanoid} from "nanoid";  
import {connect} from "react-redux";  
import {BAction} from "../../redux/actions/b-action";  class BUI extends Component {  
nameRef=createRef();  
ageRef=createRef();  addUser=()=>{  
let id=nanoid();  
let name=this.nameRef.current.value;  
let age=this.ageRef.current.value;  
this.props.addBUser({id,name,age});  
}  
render() {  
return (  
<div>  
<h2>我是组b件</h2>  
<input type="text" ref={this.nameRef} placeholder="name"/>  
<input type="text" ref={this.ageRef} placeholder="age"/>  
<button onClick={this.addUser}>添加用户</button>  
</div>  
);  
}  
}  export default connect(state=>({buser:state.breducer}),{addBUser:BAction})(BUI);
  • 最终效果如下,b组件添加用户,会在a组件中展示

image.png

  • 组件数据的交互,关键在于给某个组件state赋值的时候,{auser:state.areducer,buser:state.breducer}

  • 注意数组和对象的地址引用,这种引用只对比引用地址是否一致,并不会对比地址指向的数据是否一致,从而导致页面不会更新。

redux-devtool

拓展安装 npm install redux-devtools-extension --legacy-peer-deps

//引入store  
import {combineReducers, createStore} from "redux"  
//引入reducer  import {aReducer} from "./reducers/a-reducer"  
import {bReducer} from "./reducers/b-reducer"  
//引入devtools  
import {composeWithDevTools} from "redux-devtools-extension"  
//将多个reducer写入一个对象 注意是key=>value 格式书写  
const rootReducer = combineReducers({  
"areducer":aReducer,  
"breducer":bReducer  
})  
export default createStore(rootReducer,composeWithDevTools())

打包

执行打包命令npm run build开始编译,编译完毕,会在项目根目录生成一个build目录,我们启动一个服务器指定目录即可执行
比如我使用go作为服务器来执行build目录,即可正常访问目录,用nginx,node也是同理

package mainimport ("fmt""net/http""os"
)func main() {//     设置静态文件目录为React应用程序的build文件夹路径fmt.Println(os.Getwd())fs := http.FileServer(http.Dir("./tmp/build"))// 创建一个处理静态文件的handlerhttp.Handle("/", fs)// 启动服务器并监听端口err := http.ListenAndServe(":8088", nil)if err != nil {panic(err)}
}

image.png

  • 我们也可以使用serve来启动项目
    安装serve$ npm install -g serve,启动serve,在build同目录下,serve build即可启动服务。
    一般上线的话需要搭配node 或者nginx来启动。

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

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

相关文章

Python 多线程大批量处理文件小程序

说明 平时偶尔需要进行重复性的对文件进行重命名、格式转化等。假设以文件复制功能作为目标&#xff0c;设计一个小程序使用多线程对文件进行批量复制。&#xff08;其实以后主要目标是针对Realsense的raw文件进行批量的转化&#xff0c;并借助多线程加速&#xff09; 代码 i…

uv 必备的工具 ps ai 全家桶合集

非常稀有的资源 &#xff0c;必应搜索 易品资源yipinziyuan 可以找到

sqllab第二十关通关笔记

知识点&#xff1a; cookie注入 可以进行url解析错误注入传参位置 get请求post请求cookie传参 输入admin admin进行登录&#xff0c;抓取当前数据包 通过放包发现是一个302跳转的响应包&#xff0c;页面只有一个 I Love Cookies&#xff1b;没什么信息 通过点击页面上方的按钮…

若你有才能,最好能遇上识才之人,高俅发迹的故事很好诠释了千里马与伯乐的关系

若你有才能&#xff0c;最好能遇上识才之人&#xff0c;高俅发迹的故事很好诠释了千里马与伯乐的关系 其实&#xff0c;“千里马”和“伯乐”都是中国古代传说里的角色。伯乐是古代一个善于相马&#xff08;识别马的好坏&#xff09;的人&#xff0c;而“千里马”则是指一匹能跑…

前端学习之css样式 背景样式、字体样式、列表样式、边框样式、内外边距元素属性的转换

背景样式 html文件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>背景样式</title><link rel"stylesheet" href"../css/3.1背景样式.css"> </head> <bo…

python之万花尺

1、使用模块 import sys, random, argparse import numpy as np import math import turtle import random from PIL import Image from datetime import datetime from math import gcd 依次使用pip下载即可 2、代码 import sys, random, argparse import numpy as np imp…

通俗易懂的Python循环讲解

循环用于重复执行一些程序块。从上一讲的选择结构&#xff0c;我们已经看到了如何用缩进来表示程序块的隶属关系。循环也会用到类似的写法。 for循环 for循环需要预先设定好循环的次数(n)&#xff0c;然后执行隶属于for的语句n次。 基本构造是 for 元素 in 序列: statemen…

云原生 IaaS 服务:构建下一代云计算基础设施

随着云计算技术的不断演进&#xff0c;云原生成为了现代应用开发和部署的主流趋势。在当今这个快速变化的数字化时代&#xff0c;企业越来越需要灵活、可伸缩、自动化的基础设施来支持他们的业务需求。而云原生 IaaS&#xff08;Infrastructure as a Service&#xff09;服务则…

html--宠物

文章目录 htmljscss html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>CodePen - Spaceworm</title><script> window.requestAnimFrame (function() {return (window.requestAnimat…

[HDCTF 2023]enc

32位 这里后面运行这个程序居然要 Visual Studio&#xff0c;不然运行不了 IDA打开&#xff0c;直接锁定main函数 看见v9&#xff0c;四个32位&#xff0c;就想到了tea加密 、 标准tea from ctypes import * #tea def decrypt(v, k):v0 c_uint32(v[0])v1 c_uint32(v[1])…

代码随想录阅读笔记-字符串【反转字符串】

题目 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 你可以假设数组中的所有字符都是 ASCII 码表中的可打印…

未来已来:科技驱动的教育变革

我们的基础教育数百年来一成不变。学生们齐聚在一个物理空间&#xff0c;听老师现场授课。每节课时长和节奏几乎一致&#xff0c;严格按照课表进行。老师就像“讲台上的圣人”。这种模式千篇一律&#xff0c;并不适用于所有人。学生遇到不懂的问题&#xff0c;只能自己摸索或者…

Linux查看硬件型号详细信息

1.查看CPU &#xff08;1&#xff09;使用cat /proc/cpuinfo或lscpu &#xff08;2&#xff09;使用dmidecode -i processor Dmidecode 这款软件允许你在 Linux 系统下获取有关硬件方面的信息。Dmidecode 遵循 SMBIOS/DMI 标准&#xff0c;其输出的信息包括 BIOS、系统、主板、…

UE4_调试工具_绘制调试球体

学习笔记&#xff0c;仅供参考&#xff01; 效果&#xff1a; 步骤&#xff1a; 睁开眼睛就是该变量在此蓝图的实例上可公开编辑。 勾选效果&#xff1a;

【Linux】进程与可执行程序的关系fork创建子进程写实拷贝的理解

一、进程与可执行程序之间关系的理解 系统会将此时在系统运行的进程的各种属性都以文件的形式给你保存在系统的proc目录下。运行一个程序的时候&#xff0c;本质就是把磁盘中的程序拷贝到内存中&#xff0c;当一个进程运行起来的时候&#xff0c;它本质已经和磁盘中的可执行程序…

基于springboot和mysql实现的在线考试系统

1.项目介绍 一个在线考试系统&#xff0c;考生可以注册&#xff0c;成为本平台的一个用户&#xff0c;然后进行考试&#xff0c;考完生成成绩&#xff0c;同时用户可以查询自己考试的试卷&#xff0c;可以查看试卷解析。 升级改版 新增出卷人角色&#xff0c;主要职责是进入…

滴滴 Flink 指标系统的架构设计与实践

毫不夸张地说&#xff0c;Flink 指标是洞察 Flink 任务健康状况的关键工具&#xff0c;它们如同 Flink 任务的眼睛一般至关重要。简而言之&#xff0c;这些指标可以被理解为滴滴数据开发平台实时运维系统的数据图谱。在实时计算领域&#xff0c;Flink 指标扮演着举足轻重的角色…

【C++】了解一下编码

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. ASCII编码3. unicode4. GBK5. 类型转换 1. 前言 看到string里面还有Template instantiations&#xff1a; string其实是basic_string<char>&#xff0c;它还是一个模板。 再看看wstring&#xff1…

Linux中的文件类型

一、Linux系统如何区分文件类型&#xff1f; Linux系统中不以文件后缀名来区分文件类型&#xff0c;而是通过文件属性中第一列来区分 &#xff08;Linux系统不以文件后缀名区分文件类型&#xff0c;但是不代表Linux系统不使用文件后缀名&#xff0c;LInux系统中的许多工具例如…

如果网络不好 如何下载huggingface上的模型

很多朋友网络不太好&#xff0c;有时候上不了huggingface这样的国外网站&#xff1b; 或者网络流量不太够&#xff0c;想要下载一些stable diffusion模型&#xff0c;或者其他人工智能的大模型的时候&#xff0c;看到动辄几个G的模型文件&#xff0c;不太舍得下载&#xff1b;…