useRefreshTrigger触发器模式工作流程图解

触发器模式工作流程图解

完整数据流

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        用户操作流程                              │
└─────────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
                    ┌────────────────────────┐
                    │  用户点击"编辑"按钮     │
                    └────────────────────────┘
                                 │
                                 ▼
                    ┌────────────────────────┐
                    │  进入编辑页面 EditQa    │
                    │  修改图片并保存         │
                    └────────────────────────┘
                                 │
                                 ▼
                    ┌────────────────────────┐
                    │  调用 onBack() 回调     │
                    └────────────────────────┘
                                 │
┌────────────────────────────────┴────────────────────────────────┐
│                        父组件 (列表页)                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  const [refreshTrigger, triggerRefresh] = useRefreshTrigger();  │
│                                                                  │
│  const refresh = () => {                                        │
│    query({ ... });           // ← 1. 刷新列表数据               │
│    triggerRefresh();         // ← 2. 触发图片刷新               │
│  };                                                              │
│                                                                  │
│  ┌──────────────────────────────────────────────────┐          │
│  │  triggerRefresh() 执行过程:                      │          │
│  │                                                   │          │
│  │  setTrigger(prev => prev + 1)                    │          │
│  │       │                                           │          │
│  │       ▼                                           │          │
│  │  refreshTrigger: 0 → 1 → 2 → 3 ...              │          │
│  └──────────────────────────────────────────────────┘          │
│                                                                  │
│  <FileUpload                                                    │
│    id={problem.id}                                              │
│    refreshTrigger={refreshTrigger}  // ← 传递触发器值           │
│  />                                                              │
│                                                                  │
└──────────────────────────┬───────────────────────────────────────┘
                           │ props 传递
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                    子组件 (FileUpload)                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  function FileUpload({ id, refreshTrigger }) {                  │
│    const [pictures, setPictures] = useState([]);                │
│                                                                  │
│    useEffect(() => {                                            │
│      if (id) {                                                  │
│        getFileInfos({ query: { fkId: id } })                   │
│          .then(res => setPictures(res));                        │
│      }                                                           │
│    }, [id, refreshTrigger]);  // ← 依赖 refreshTrigger          │
│                                                                  │
│    ┌──────────────────────────────────────────────┐            │
│    │  React 检测依赖变化:                         │            │
│    │                                               │            │
│    │  refreshTrigger 从 0 变成 1                  │            │
│    │       ↓                                       │            │
│    │  useEffect 重新执行                           │            │
│    │       ↓                                       │            │
│    │  发起新的图片请求                             │            │
│    │       ↓                                       │            │
│    │  setPictures(新数据)                          │            │
│    │       ↓                                       │            │
│    │  组件重新渲染,显示新图片                     │            │
│    └──────────────────────────────────────────────┘            │
│                                                                  │
│    return <img src={pictures[0].url} />;                        │
│  }                                                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

关键点解析

1. 为什么用数字而不是布尔值?

javascript 复制代码
// ❌ 使用布尔值的问题
const [refresh, setRefresh] = useState(false);

const triggerRefresh = () => {
  setRefresh(true);
  setTimeout(() => setRefresh(false), 0); // 需要重置
};

// 连续两次调用会失效:
triggerRefresh(); // true
triggerRefresh(); // 还是 true,没有变化!


// ✅ 使用数字的优势
const [trigger, setTrigger] = useState(0);

const triggerRefresh = () => {
  setTrigger(prev => prev + 1);
};

// 每次调用都会变化:
triggerRefresh(); // 0 → 1
triggerRefresh(); // 1 → 2
triggerRefresh(); // 2 → 3

2. 为什么不用 key 强制重新挂载?

javascript 复制代码
// ❌ 使用 key 的问题
<FileUpload key={`${id}-${timestamp}`} id={id} />

// 组件生命周期:
// 1. 卸载旧组件 (componentWillUnmount)
// 2. 销毁所有状态和 DOM
// 3. 挂载新组件 (componentDidMount)
// 4. 重新初始化所有状态
// 5. 重新渲染 DOM

// 性能开销大,可能导致:
// - 闪烁
// - 动画中断
// - 滚动位置丢失
// - 输入焦点丢失


// ✅ 使用 refreshTrigger 的优势
<FileUpload id={id} refreshTrigger={trigger} />

// 组件生命周期:
// 1. 组件保持挂载状态
// 2. 只执行 useEffect 回调
// 3. 只更新需要更新的数据
// 4. 保留其他状态和 DOM

// 性能好,用户体验流畅

3. 为什么要封装成 Hook?

javascript 复制代码
// ❌ 不封装的问题
function Component1() {
  const [trigger, setTrigger] = useState(0);
  const fire = () => setTrigger(prev => prev + 1);
  // ...
}

function Component2() {
  const [trigger, setTrigger] = useState(0);
  const fire = () => setTrigger(prev => prev + 1);
  // ... 重复代码
}


// ✅ 封装成 Hook 的优势
function Component1() {
  const [trigger, fire] = useRefreshTrigger();
  // 简洁、可复用
}

function Component2() {
  const [trigger, fire] = useRefreshTrigger();
  // 同样简洁
}

对比其他方案

方案 性能 易用性 可维护性 推荐度
触发器模式 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ 强烈推荐
key 强制重挂载 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⚠️ 不推荐
ref 命令式调用 ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐ ⚠️ 不推荐
布尔值切换 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐ ⚠️ 不推荐

实际应用场景

场景 1:列表刷新

javascript 复制代码
const [trigger, fire] = useRefreshTrigger();

<FlatList
  data={data}
  renderItem={({ item }) => (
    <ItemCard refreshTrigger={trigger} />
  )}
/>
<Button onPress={fire}>刷新全部</Button>

场景 2:表单重置

javascript 复制代码
const [trigger, fire] = useRefreshTrigger();

<Form resetTrigger={trigger}>
  <Input />
  <Select />
</Form>
<Button onPress={fire}>重置表单</Button>

场景 3:图表重绘

javascript 复制代码
const [trigger, fire] = useRefreshTrigger();

<Chart 
  data={chartData}
  redrawTrigger={trigger}
/>
<Button onPress={fire}>刷新图表</Button>

场景 4:WebSocket 重连

javascript 复制代码
const [trigger, fire] = useRefreshTrigger();

useEffect(() => {
  const ws = new WebSocket(url);
  // ... 连接逻辑
  return () => ws.close();
}, [trigger]);

<Button onPress={fire}>重新连接</Button>

总结

触发器模式的本质是:

通过一个简单的、可预测的值变化,来触发复杂的、可控的副作用

这种模式:

  • ✅ 符合 React 的声明式理念
  • ✅ 保持单向数据流
  • ✅ 性能优秀
  • ✅ 易于理解和维护
  • ✅ 可复用性强

掌握这个模式,你就掌握了 React 状态管理的精髓!

相关推荐
墨狂之逸才17 小时前
react native项目中使用React Hook 高级模式
react native
wayne2141 天前
React Native 状态管理方案全梳理:Redux、Zustand、React Query 如何选
javascript·react native·react.js
Mintopia2 天前
🎙️ React Native(RN)语音输入场景全解析
android·react native·aigc
程序员Agions2 天前
React Native 邪修秘籍:在崩溃边缘疯狂试探的艺术
react native·react.js
chao_6666663 天前
React Native + Expo 开发指南:编译、调试、构建全解析
javascript·react native·react.js
_pengliang3 天前
react native ios 2个modal第二个不显示
javascript·react native·react.js
wayne2143 天前
React Native 0.80 学习参考:一个完整可运行的实战项目
学习·react native·react.js
坚果派·白晓明4 天前
Windows 11 OpenHarmony版React Native开发环境搭建完整指南
react native·开源鸿蒙·rnoh
开心不就得了5 天前
React Native对接Sunmi打印sdk
javascript·react native·react.js