React 正式更新!开始学习 React 19!
本文为原创文章,原文链接:J实验室,未经授权请勿转载
今年2月份,React 发布消息确认今年发布 v19 版本,尘封两年的版本号终于要更新了(详情点击:React 19 发布在即,抢先学习一下新特性)。那时候,React 成员 Andrew Clark 明确了新版本将在3月或4月发布。
要不怎么说「DDL是第一生产力」,这不4月底了,新版本就踩点发布了。这次发布的版本号是19.0.0-Beta。
虽然只是 Beta 版,但也够让社区兴奋了:
Dan 说「they did what」
Andrew Clark 说「React 19: Never forwardRef again」
Josh W. Comeau 说「Lots of nice quality-of-life improvements here!」
唯一的遗憾是,经 React 成员 lauren 确认,React Compiler 又跳票了。这个东西原来的名称叫做「React Forget」,真就是 Forget 属性拉满了。
总结一下 19.0.0-Beta 版本的发布的特性就是:
- 一个 Actions
- 三个新 hook
- 一个新 API
- ref 和 context 用法更方便
- 其他支撑类更新、服务端能力更新
接下来本文一个个介绍。
????欢迎加入「????独立全栈开发交流群」,一起学习交流前端和Node技术
Action
Actions 不是一个 API,是一种简化请求数据处理的方法统称。一个合格的 Actions 要能够简化异步操作,让开发者更专注于业务逻辑而不是状态管理。
让我们通过一个简单的例子来理解Actions的作用。假设我们有一个表单,用户可以通过该表单更新他们的姓名。以前,我们可能会使用useState来手动管理表单状态、错误状态和提交状态,代码可能会看起来像这样:
function UpdateName() {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);
const handleSubmit = async () => {
setIsPending(true);
const error = await updateName(name);
setIsPending(false);
if (error) {
setError(error);
return;
}
redirect("/path");
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>
Update
</button>
{error && <p>{error}</p>}
</div>
);
}
这段代码需要手动处理许多细节。但是,有了 React 19 的 Actions,情况就有所优化,我们可以使用 useTransition
hook 来处理表单提交,它会自动处理 pending 状态,让我们的代码更加简洁:
function UpdateName() {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const handleSubmit = async () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect("/path");
})
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>
Update
</button>
{error && <p>{error}</p>}
</div>
);
}
在 handleSubmit
函数中,异步请求的逻辑被放入 startTransition
的回调中。startTransition
被调用时,React 会立即将 isPending
设为 true,表示过渡(请求)正在进行。然后 React 会在后台执行 startTransition
的回调函数,发送异步请求。在请求完成后,React 会自动将 isPending
切换为 false。
我们只要将 isPending
绑定到提交按钮的 disabled
属性,这样在请求进行期间按钮会自动进入禁用状态,避免用户重复提交。
下面总结一下 React 对 Actions 的约定和说明:
- 命名约定:使用异步过渡的函数可以被称为“Actions”。
- 挂起状态:Actions 自动管理提交数据的挂起状态。当发起请求时,挂起状态会自动启动,当最终状态更新后,挂起状态就会自动重置。这样可以确保用户在等待数据提交时能够获得反馈,同时在请求完成后清除挂起状态。
- 乐观更新:Actions 支持乐观更新,即在等待请求提交时就向用户显示正确的提交结果。如果最终请求失败,乐观更新会自动恢复到其原始值。
- 错误处理:Actions 提供了内置的错误处理功能。当请求失败时,你可以使用错误边界来显示错误信息。
-
表单支持:
<form>
元素现在支持将函数传递给action
和formAction
属性。通过将函数传递给action
属性,可以使用 Actions 来处理表单提交,默认情况下会在提交后自动重置表单。这简化了表单处理的过程,使其更加直观和高效。
三个新 Hook
为什么要先介绍 Actions 呢?因为 React 19 在 Actions 基础上引入了三个新 Hook,每一个都是为了简化开发者操作状态的复杂度。
useOptimistic
useOptimistic
的主要目的是让我们可以在等待异步操作结果的时候,先假设操作成功并更新状态,然后再根据实际结果来确认状态。
它的基本用法如下:
import { useOptimistic } from 'react';
function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
}
);
}
其中:
-
state
: 初始状态和没有正在进行的操作时返回的状态。 -
updateFn(currentState, optimisticValue)
: 一个纯函数,接受当前状态和addOptimistic
传入的乐观更新值,返回合并后的乐观状态。 -
optimisticState
: 乐观状态,如果没有正在进行的操作,则等于state
,否则等于updateFn
的返回值。 -
addOptimistic
: 一个用于触发乐观更新的函数,接受一个任意类型的optimisticValue
参数,并将其传递给updateFn
。
useOptimistic
的使用场景非常广泛,例如:表单提交、点赞、收藏、删除等需要即时反馈的场景均适用。
这是一个删除数据乐观更新的例子:
import React, { useState } from 'react';
import { useOptimistic } from 'react';
function AppContainer() {
// 默认数据
const [state, setState] = useState([
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
]);
// 定义更新函数,该函数基于当前状态和乐观值(要删除的条目的ID)来更新状态
const updateFn = (currentState, optimisticId) => {
return currentState.filter(item => item.id !== optimisticId);
};
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
// 删除item
const deleteItem = async (itemId) => {
// 首先乐观地更新 UI
addOptimistic(itemId);
// 模拟 API 请求延迟
setTimeout(() => {
// 假设这里是 API 删除调用,完成后更新实际状态
setItems(currentItems => currentItems.filter(item => item.id !== itemId));
}, 2000);
};
return (
<div>
<h1>Optimistically Deleting Items</h1>
<ul>
{optimisticState.map(item => (
<li key={item.id}>
{item.name} <button onClick={() => deleteItem(item.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default AppContainer;
useActionState
useActionState
原名叫做 useFormState
,19版本启用新名称,返回参数也发生了变化(奇怪的是,React 还未更新 useActionState
的文档,欺负程序员不看文档吗?????)。
这是 useActionState 的最新基本用法:
const [state, action, pending] = useActionState(fn, initialState, permalink?);
其中返回参数有:
-
state
: 表示当前的状态。在第一次渲染时,它等于初始状态initialState
。在执行操作后,它将是最新结果。 -
action
: 这是一个函数,用于执行操作。当调用这个函数时,它将触发fn
函数的执行,并更新状态。 -
pending
: 这是新增参数,它是一个布尔值,表示当前是否正在执行操作。如果正在执行操作,则为true
,否则为false
。
传入的参数有:
-
fn
:这是一个函数,action被调用时会触发,随后返回新的值。 -
initialState
:这是初始值,如果没有初值,要设置为null。 -
permalink
:这是一个可选的字符串参数,通常与server action一起使用。
下面是 useActionState
与 form action 一起使用的例子,实现了更新名称的功能,如果更新失败,页面上显示 error,如果更新成功,跳转到更新后的页面:
import { useActionState } from 'react';
function ChangeName({ name, setName }) {
// 使用 useActionState 创建与表单操作相关联的状态
const [error, submitAction, isPending] = useActionState(
// 第一个参数:表单操作函数
async (previousState, formData) => {
// 在此定义表单操作的逻辑
// 这个函数会在表单提交时被调用
// 它接收两个参数:
// - previousState: 前一个状态,初始为 null,之后为上一次操作的返回值
// - formData: 表单数据对象,可通过 formData.get("name") 获取表单字段的值
const error = await updateName(formData.get("name"));
// 如果操作中出现了错误,则返回错误信息
if (error) {
return error;
}
// 如果操作成功,则执行重定向
redirect("/path");
},
// 第二个参数:初始状态,这里为 null,因为初始状态并不重要
null
);
// 返回表单及相关的状态和行为
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>
提交
</button>
{/* 错误信息 */}
{error && <p>{error}</p>}
</form>
);
}
useFormStatus
useFormStatus
用来获取表单提交的状态信息。它的基本用法如下:
const { pending, data, method, action } = useFormStatus();
其中:
-
pending
: 一个布尔值,表示父级<form>
是否正在提交。如果为true
,表示表单正在提交,否则为false
。 -
data
: 一个实现了 FormData 接口的对象,包含父级<form>
正在提交的数据。如果没有正在进行的提交或没有父级<form>
,则为null
。 -
method
: 一个字符串值,表示父级<form>
使用的 HTTP 方法,可以是 get 或 post。 -
action
: 一个指向传递给父级<form>
的 action 属性的函数的引用。如果没有父级<form>
,则该属性为null
。
例如,在 form action 中,开发者可以通过 useFormStatus
获取表单状态:
import { useFormStatus } from "react-dom";
import action from './actions';
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}
export default function App() {
return (
<form action={action}>
<Submit />
</form>
);
}
这个写法是不是熟悉又陌生?如果你想到了 context,那就对了,你可以理解为 useFormStatus
替代了一部分 context provider 的能力,而且写法比 context 要更加简洁。
使用 useFormStatus
还有两个注意点:
-
useFormStatus
Hook 必须在渲染在<form>
内部的组件中调用。 -
useFormStatus
只会返回父级<form>
的状态信息,而不会返回同一组件或其子组件中任何其他<form>
的状态信息。
一个新 API——use
以前 use
是被归类到 hook,但是 19 版本的文档把 use
放在 API 文档里面,所以它就成了一个新的 API 啦!
use 用于在组件中读取资源的值,这个资源可以是一个 Promise 或者一个 context。
它的基本用法如下:
const value = use(resource);
在实际代码中可能是这样:
import { use } from 'react';
function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
const theme = use(ThemeContext);
// ...
use 主要是给 Next.js 这样的上层框架使用的。以 Next.js 为例,如果是在服务端组件中获取数据,更推荐使用 async…await,而不是 use。如果是在客户端组件中获取数据,也推荐在服务端组件里创建 Promise,以 props 传递给客户端组件调用。
use 还可以与 Suspense 边界共用。如果调用 use
的组件被包裹在一个 Suspense 边界内,会显示指定的 fallback。一旦 Promise 被 resolve,Suspense 的 fallback 就会被返回的数据替换。如果传给 use
的 Promise 被 reject,最近的错误边界的 fallback 将会被显示。
ref 和 context 用法简化
如果你只使用 React 客户端的能力,那么这一节介绍的变更会是你最关注的。
ref 抛弃 forwardRef
你还记得被 forwardRef
支配的恐惧吗?从 React 19 开始,我们可以抛弃 forwardRef
了。现在开始,ref 可以当作 prop 进行传递。
举个例子:假设我们有一个函数组件 TextInput
,它是一个简单的输入框组件,接受一个 placeholder
属性用于设置输入框的占位符文本。现在,我们希望在父组件中获取到输入框的引用,以便在需要时聚焦到输入框上,代码可以这么写:
import React, { useRef } from 'react';
// 定义一个函数组件 TextInput
function TextInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// 父组件
function ParentComponent() {
// 创建一个 ref 来存储输入框的引用
const inputRef = useRef(null);
// 在某个事件处理函数中获取输入框的引用并聚焦
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
{/*
将 inputRef 传递给 TextInput 组件,
这样 TextInput 组件内部就可以使用这个 ref 了
*/}
<TextInput placeholder="Enter your name" ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
export default ParentComponent;
是不是心智负担比使用 forwardRef 要轻得多?
context 可当作 provider
从在 React 19 开始,开发者可以直接将 <Context>
直接作为 provider,而不是使用 <Context.Provider>
。
假设我们有一个名为 ThemeContext
的 context,用于管理主题信息。在 React 19 中,我们可以像下面这样使用 <ThemeContext>
作为提供者:
import React, { createContext } from 'react';
// 创建一个主题上下文
const ThemeContext = createContext('');
// App 组件作为主题提供者
function App({ children }) {
return (
<ThemeContext value="dark">
{children}
</ThemeContext>
);
}
未来 ThemeContext.Provider
会被弃用并移除。
其他更新
本次发布的新特性还有一些属于支撑类特性和拓展服务端能力的特性,因为纯客户端的 React 开发中使用场景很少,所以不再详细介绍,只简单提炼要点:
-
服务端组件和
server actions
将成为稳定特性,这两个概念属于熟悉 Next.js/Remix 的人已经烂熟于心,而不用 Next.js/Remix 的人根本用不到。 -
useDeferredValue
增加了第二个参数,可选,用来表示初始值。即现在useDeferredValue
的用法是这样:const value = useDeferredValue(deferredValue, initialValue?);
-
支持在 React 代码里编写 document metadata,即在页面组件编写
<title>
<link>
和<meta>
标签会自动添加应用的<head>
上面:function BlogPost({post}) { return ( <article> <h1>{post.title}</h1> <title>{post.title}</title> <meta name="author" content="Josh" /> <link rel="author" href="https://twitter.com/joshcstory/" /> <meta name="keywords" content={post.keywords} /> <p> Eee equals em-see-squared... </p> </article> ); }
-
支持在 React 代码里编写 stylesheets,即在页面组件编写
<link rel="stylesheet" href="...">
-
支持在 React 代码里编写
<script async="" src="...">
,最终也会自动添加到<head>
标签内 -
支持预加载资源,最终也会自动添加到
<head>
标签内:import { prefetchDNS, preconnect, preload, preinit } from 'react-dom' function MyComponent() { preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet prefetchDNS('https://...') // when you may not actually request anything from this host preconnect('https://...') // when you will request something but aren't sure what }
总结
最后,让我用黄玄的一段话作为总结:「Probably the single most critical principle I’ve learned from React is to be fearless in defining new conceptual abstractions and never compromise on the accuracy and composability of these definitions——我从 React 身上学到的最重要的一条原则可能就是,在定义新的概念抽象时要无所畏惧,绝不要在这些定义的准确性和可组合性上妥协」。
关于我
全栈工程师,Next.js 开源手艺人,AI降临派。
今年致力于 Next.js 和 Node.js 领域的开源项目开发和知识分享。
欢迎来交个朋友~
上一篇: 美国国防部发布 DevSecOps 持续授权实施指南(上)
下一篇: js执行顺序
推荐阅读
-
React 正式更新!开始学习 React 19!
-
React|新手指南 - 我终于开始学习 React 了!
-
好吧,我要开始学习 React(基础 II)
-
好吧,我要开始学习 React(基金会 III)了,这真是一个伟大的写作时刻!
-
好了,我要开始学习 React(基础 1)
-
41 个下载免费 3D 模型的最佳网站-使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 17. Clara.io Clara.io 是一个创建 3D 内容的全球平台,也是一个培养新 3D 艺术家的社区。Clara.io 提供+100,000个免费的3D模型,包括OBJ,Blend,STL,FBX,DAE,Babylon.JS,Three.JS格式,用于 Clara.io,Unity 3D,Blender,Sketchup,Cinema 4D,3DS Max和Maya。 使用说明:免费,标准和专业帐户仅供个人使用,如果您需要将 clara.io 用于商业用途,请与销售团队联系。 18. 3DExport 3DExport是一个市场,您可以在其中购买和销售用于CG项目的3D模型,3D打印模型和纹理。它提供15 +不同的3D格式供下载,如3DS MAX(.max),Cinema4D(.c4d),Maya(.mb,.ma),Lightwave(.lwo),Softimage(.xsi),Wavefront OBJ(.obj),Autodesk FBX(.fbx)等。它还提供15种不同的语言! 使用说明:免费下载仅供个人和非商业用途。 19. 3D Warehouse 3D Warehouse是一个开放的库,允许用户共享和下载SketchUp 3D模型,用于建筑,设计,施工和娱乐!任何人都可以免费制作,修改和重新上传内容到3D仓库,您可以找到任何您能想到的东西,如家具,电子产品,室内产品等。 使用说明:3D Warehouse中的所有模型都是免费的,因此任何人都可以下载文件以用于SketchUp甚至其他软件,如AutoCAD,Revit和ArchiCAD。 20. CadNav.com CadNav是CGI平面设计师和CAD / CAM / CAE工程师的在线3D模型库,我们提供超过50000 +免费3D模型和CAD模型下载。在CadNav网站上,您可以下载高质量的多边形网格3D模型,3D CAD实体对象,纹理,Vray材料,3D作品,CAD图纸等。 使用说明:免费下载仅供个人和非商业用途。 21. All3dfree.net 就像网站名称一样,它提供免费的3D模型,还包括Vray材料,CAD块,2d和3d纹理集合,无需注册即可免费下载。它是不断更新的,因此您可以查找或请求3DS,MAX,C4D,skp,OBJ,FBX,MTL等格式的模型。 使用说明:所有资源均不允许用于商业用途,否则您将承担责任。 22. Hum3D 自2005年以来,Hum3D帮助来自3多个国家的80D艺术家节省3D建模时间,并制作逼真的3D模型,用于电影,视频游戏,AR应用程序和可视化。所有模型均由首席3D艺术家进行验证,他们检查其是否符合专业要求和最新的3D建模标准。 使用说明:免费下载仅供个人和非商业用途。 23. Artist-3D.com 艺术家-3D 库存的免费 3D 模型下载按通用类别排序。它为人体解剖学、汽车、家具、火箭、卫星等模型提供 AutoDesk 3DS Max 格式。您还可以在浏览他们的网站时找到教程和类似类型的建模。 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 24. Free the models 就像本网站的标题一样,它为3d应用程序和3d游戏引擎提供免费的内容模型。您可以为您的任何项目找到许多有趣且有用的模型!它提供3ds,wavefront,bryce,poser,lightwave,md2和unity3d格式的模型。还有一个很棒的纹理集合,可以在您最喜欢的建模和渲染程序中使用。 使用说明:您从这里下载的所有内容都可以免费使用,除非它不能包含在另一个免费的网络或CD收藏中,也不能单独出售。否则,您可以在商业游戏,3D应用程序或渲染作品中使用它。您不必提供信用,但如果您这样做,那就太好了。 25. Resources.blogscopia 本网站由一家名为Scopia的公司创建。他们制作3D图像和视频,您可以找到许多为CGI工作的信息架构设计的模型,所有这些都可以在现实生活中使用。您可以免费下载它们,但是,如果您想一次下载它们,您可以支付 3 到 9 欧元。 使用说明:您可以免费下载模型部分的所有文件。每个压缩文件都包含您也可以在此处找到的许可证。基本上,您可以对文件执行任何操作。唯一的限制是不归属于Scopia的重新分发。 26.ambientCG 1000+公共领域PBR材料适合所有人!环境CG是使用许多不同的方法和资产类型创建的,例如照片纹理(PBR),贴花(PBR),图集(PBR),照片纹理(普通),物质存档(SBSAR),雕刻画笔,3D模型和地形。您可以在所有项目中*使用它们! 使用说明:在 ambientCG 上提供下载的所有 PBR 材料、画笔、照片和 3D 模型均根据知识共享 CC0 1.0 通用许可提供。您可以复制、修改、分发和执行作品,即使是出于商业目的,也无需征得许可。信用将不胜感激。 不要满足于平庸的大理石纹理 - 立即使用我们的免费PBR大理石纹理升级您的3D设计。 27.Pixar One Twenty Eight 这是一个提供官方动画行业经典纹理的网站:皮克斯,创建于 1993 年,该纹理库包括 128 个重复纹理,现在免费提供。 它包含您来到的纹理,包括砖块和动物毛皮。肯定会有一些你可以使用的东西。 使用说明:皮克斯动画工作室的《Pixar One Twenty Eight》根据知识共享署名4.0国际许可协议进行许可。即使出于商业目的,您也可以重新混合、调整和构建您的作品,只要您以相同的条款对新创作进行信用和许可。 访问数以千计的免费纹理并提升您的设计游戏 - 立即开始下载! 28. 3DXO 即使有近 620 个免费贴纸可供下载,3DXO 也不是最大的资源,但它的内容非常有用,不需要注册。无论是简单的墙壁或地板,还是一些奇怪的小东西,您都需要的纹理都可以在此网站上看到。 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 29. 3DModelsCC0 3DModelsCC0 与其他产品的不同之处在于它包含超过 250+ 个高质量 3D 模型,并且本网站上的所有内容都是免费的,完全是公共领域!使用我们的模型时无需信用或归属! 使用说明:为每个人提供完全免费的公共领域内容。 30.Sketch up texture club Sketchup Texture Club是一个非营利性的教育和信息门户网站,由3D社区的图像促进协会管理,特别强调面向学生和建筑和室内设计专业人士的可视化和渲染技术,以及所有正在学习3D可视化的人。 使用说明:您无需支付版税或使用费。纹理可以免费下载和使用。不允许将纹理作为竞争产品出售或重新分发,即使图像被修改也是如此。 31. FlippedNormals FlippedNormal 是一个提供计算机图形和 3D 资产的市场,您可以找到许多用于雕刻、建模、纹理、概念艺术、3D 模型、游戏资产或课程的高级资产! 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 32. NASA 3D NASA 3D网站是一个在线门户,提供与太空和各种NASA任务相关的大量三维模型和模拟。该网站是用户友好的,并提供有关每个型号的详细信息。该网站允许用户探索和下载几种不同格式的模型,包括 OBJ、STL 和 FBX,只需单击下载按钮即可。 使用说明: 要下载模型,只需单击模型页面上的下载按钮并选择所需的格式。 33. 3DAGOGO (Astroprint) 3DAGOGO 是一个提供广泛 3D 模型的网站,包括角色、车辆和建筑物。3DAGOGO 的独特功能之一是它专注于适合 3D 打印的模型,使其成为希望创建物理原型或模型的设计师的绝佳资源。要使用 3DAGOGO,设计师只需在网站上搜索他们正在寻找的模型类型,然后下载 STL 格式的文件。 使用说明: 要使用 3DAGOGO,只需搜索所需的 3D 模型类型并下载 STL 格式的文件。根据需要自定义模型,并确保在将其用于商业目的之前检查使用权限。 34. FreeCAD FreeCAD是一款了不起的3D建模软件,可让您在计算机上创建令人难以置信的3D设计。该软件可免费下载和使用,它提供了广泛的工具和功能,可用于创建用于各种目的的3D模型。 该网站易于浏览,您可以找到开始使用FreeCAD的所有必要信息。此外,该网站还提供一系列教程和指南,可帮助您了解 3D 建模的来龙去脉。 使用说明: 要下载模型,请访问网站并从库中选择所需的模型。该网站还提供了一系列使用该软件的教程和指南。 35. Pinshape Pinshape是一个提供一系列3D打印模型的网站。网站上提供的型号质量很高,因此您可以确保您的最终印刷产品看起来很棒。该网站提供了广泛的模型,包括从家居用品到小雕像和珠宝的所有物品。 但这还不是Pinshape所能提供的全部!该网站还允许用户上传和共享自己的3D模型。这意味着您不仅可以下载出色的模型,还可以通过分享自己的设计为社区做出贡献。此外,Pinshape 提供了一系列自定义选项,因此您可以调整和调整模型以满足您的特定需求。 使用说明: 要下载模型,请在网站上创建一个帐户,搜索所需的模型,然后单击下载按钮。该网站还为每种型号提供了一系列定制选项。 36.Yeggi Yeggi 提供了大量免费的 3D 模型,您可以下载各种格式的模型,例如 STL、OBJ 和 FBX。该网站易于使用,您可以按关键字、类别或特定网站搜索模型。 Yeggi 对于任何寻找 3D 模型的人来说都是一个很好的资源。它提供了大量的模型集合,从日常物品到复杂的机械,以及介于两者之间的一切。该网站的收藏量在不断增长,每天都有新的型号增加。 使用说明: 要下载模型,请在网站上搜索所需的模型,然后单击下载按钮。该网站还提供指向托管模型的原始网站的链接。 37. Open3DModel 来自开放3D模型的图像 Open3DModel具有各种类别的模型,包括建筑,车辆和角色。无论您需要建筑物,汽车还是人的3D模型,都可以在此网站上找到。 该网站易于浏览,您可以按类别或关键字搜索模型。每个模型都附带预览图像和详细信息,例如文件格式、大小和多边形数量。此信息可以帮助您选择适合您需求的模型。 使用说明: 要下载模型,请访问网站,从库中选择所需的模型,然后单击下载按钮。 使用最好的 3D 资产管理工具简化您的 3D 制作流程。立即试用它们,将您的 3D 项目提升到一个新的水平! 38. 3DExport 对于那些为其 3D 设计项目寻找 3D 模型、纹理和其他资源的人来说,该平台是一个很好的资源。该网站有大量模型可供选择,包括 3D 打印对象、游戏资产等。用户可以按类别、文件格式或价格范围浏览,以找到适合其项目的完美资源。此外,3DExport 还提供一系列教程和其他 3D 资源,以帮助用户提高技能并创建更令人印象深刻的设计。 使用说明: 要使用 3DExport,只需创建一个帐户并浏览可用型号。您可以按类别、格式和价格进行搜索,以找到所需的型号。找到喜欢的模型后,只需下载它并开始在您的项目中使用它。 39.Blend Swap Blend Swap是一个社区驱动的市场,提供与Blender软件兼容的各种免费3D模型。该平台允许用户共享和下载模型、纹理和其他资产,以便在他们的项目中使用。 使用说明: 创建免费帐户后,您可以浏览社区上传的大量3D模型。当您找到要使用的一个时,只需下载它并将其导入您选择的 3D 软件即可。 40. 3DShook 3DShook 是一个高级 3D 模型市场,提供一系列用于建筑、游戏等各个行业的高质量模型。该平台提供基于订阅的模型,具有不同的定价计划,允许用户访问一系列模型。 使用说明: 注册免费帐户后,只需浏览3D模型库,选择您喜欢的模型,然后以您需要的格式下载它们。 41. Smithsonian X 3D 史密森尼 X 3D 对于正在寻找历史文物和文物的高质量 3D 模型的设计师来说,这是一个独特的资源。该平台提供了大量3D模型,这些模型是根据史密森尼博物馆和研究中心中的真实物体扫描创建的。 使用说明: