😀 大家好: 这次我以一个实际学习的 Web3 项目为例,一步步了解 React 开发中的重要概念。最近学习前端的知识,深知入门时的困惑,所以这次用最通俗的语言,结合实际代码来学习。
⚠️这次的代码示例,用的是HOH老陈老师给我们提到一个典范用例去学习。
1. 项目结构:你的代码应该放在哪里?
首先,让我们看看一个典型的 React 项目是怎么组织的:
bash
src/
├── components/ # 可重用的组件
│ ├── ui/ # 基础UI组件
│ └── business/ # 业务组件
├── pages/ # 页面组件
├── lib/ # 工具函数和库
├── type/ # TypeScript 类型定义
├── App.tsx # 应用程序的主入口
└── main.tsx # 渲染入口
这就像是整理你的房间:
components
就像你的工具箱,放着经常用到的小工具pages
就像房间的不同区域,每个区域有特定的用途lib
就像是收纳盒,存放各种通用的小物件type
就像是使用说明书,告诉大家东西该怎么用
2. 路由:如何在页面间切换?
看看我们的 App.tsx
:
javascript
function App() {
return (
<Router>
<div className="bg-background">
<NaviBar />
<Routes>
<Route path="/" element={<Main />} />
<Route path="/user" element={<User />} />
</Routes>
</div>
</Router>
);
}
这就像是给你的网站画了一张地图:
Router
就是整个地图的边框Routes
就像是地图上的路线Route
就是具体的目的地path="/"
就是主页,像家的位置path="/user"
就是用户页面,像是你常去的商店
3. 组件:积木游戏
导航栏组件:
javascript
function NaviBar() {
return (
<nav className="flex items-center justify-between p-4">
<div className="flex items-center space-x-4">
<Link to="/">首页</Link>
<Link to="/user">用户</Link>
</div>
<WalletStatus />
</nav>
);
}
组件就像乐高积木:
- 每个组件都是一个独立的积木块
Link
组件就像是门,让你能去到其他房间className
就像是积木的颜色和形状WalletStatus
是另一个积木块,专门显示钱包状态
4. Hooks:组件的记忆力
基础 Hooks
scss
function UserProfile() {
// 状态管理:就像是记事本
const [profile, setProfile] = useState(null);
// 就像是定时任务
useEffect(() => {
// 获取用户资料
fetchUserProfile();
}, []);
// 回调函数:就像是预设好的操作指南
const handleUpdate = useCallback(() => {
updateProfile();
}, []);
}
自定义 Hooks (复用)
scss
function useWallet() {
const [isConnected, setIsConnected] = useState(false);
const [balance, setBalance] = useState(0);
useEffect(() => {
// 监听钱包连接状态
const checkConnection = async () => {
// 检查逻辑
};
checkConnection();
}, []);
return { isConnected, balance };
}
Hooks 就像是给组件装上了不同功能的芯片:
useState
就像是记事本,能记住数字、文字等信息useEffect
就像是一个自动执行的任务清单[]
依赖数组就像是触发条件,告诉任务什么时候该执行
5.状态管理进阶
本地状态管理
csharp
const [displayProfile, setDisplayProfile] = useState<DisplayProfile | null>(null);
就像是组件的私人笔记本:
- 只有自己能看到和修改
- 数据变化时会自动更新界面
- 适合管理组件内部的临时数据
全局状态管理
javascript
const WalletContext = React.createContext({
address: null,
connect: () => {},
disconnect: () => {}
})
就像是公共告示板:
- 所有组件都能看到
- 数据变化时相关组件都会更新
- 适合管理需要共享的数据
6. 样式
项目使用了 Tailwind CSS(一个样式工具库) +Shadcn (UI组件库)
css
<div className="flex items-center justify-between p-4 bg-white shadow-md">
项目中常用的几个样式:
flex
就像是把东西排成一行items-center
就像是让所有东西垂直居中p-4
就像是给内容加上内边距bg-white
就像是刷上白色油漆shadow-md
就像是给元素加上阴影,让它看起来立体一点
我个人的学习方法是样式部分基本都是现用现查,不去记忆。
7.智能合约交互
查询链上状态
tsx
export const queryState = async () => {
const events = await suiClient.queryEvents({
query: {
MoveEventType: `${networkConfig.testnet.packageID}::week_two::ProfileCreated`
}
})
const state: State = {
users: []
}
events.data.map((event) => {
const user = event.parsedJson as User;
state.users.push(user);
})
return state;
}
这就像是:
- 查看区块链上的"公告板"
- 找到所有创建用户档案的记录
- 整理成前端可以使用的格式
查询用户档案
tsx
export const queryProfile = async (address: string) => {
if (!isValidSuiAddress(address)) {
throw new Error("Invalid profile address");
}
const profileContent = await suiClient.getObject({
id: address,
options: {
showContent: true
}
})
// ... 数据处理逻辑
}
- 先检查地址是否有效
- 根据地址查找用户的档案
- 将链上数据转换为可用格式
8.交易处理
创建用户档案
tsx
export const createProfileTx = (name: string, description: string) => {
return Transaction.create()
.moveCall({
target: `${networkConfig.testnet.packageID}::week_two::create_profile`,
arguments: [name, description],
});
}
- 填写一份创建档案的表单
- 准备提交到区块链
- 等待区块链确认
⚠️ 在有些的智能合约和前端交互的功能会用到 PTB 交易块 or 签名交易 为的是保证交易的成功和防止篡改。
8.GraphQL 查询
部分code:
tsx
const queryFolderDataContext = graphql(`
query queryFolderDataContext($address:SuiAddress!) {
object(address:$address){
dynamicFields{
nodes{
name{
json
}
value{
...on MoveValue{
json
}
}
}
}
}
}
`)
- 一次获取多个相关数据
- 减少网络请求次数
- 更高级的查询语言
💡 有关React使用上的问题,欢迎您在底部评论区留言,一起交流~