在什么业务场景使用 use-immer

93 阅读1分钟

A代码


            if (current_knowledge.data.knowledge_base_results.length > 0 && !responseFlux.includes('paint')) {
              knowledge_list = current_knowledge.data.knowledge_base_results;
              let lastItem = chatHistoryRef.current.pop();
              lastItem[2] = knowledge_list;
              const content = [...chatHistoryRef.current, lastItem];
              setChatHistory(content);
            }

B代码


            if (current_knowledge.data.knowledge_base_results.length > 0 && !responseFlux.includes('paint')) {
              knowledge_list = current_knowledge.data.knowledge_base_results;
              let lastItem = chatHistoryRef.current.pop();
              lastItem[2] = knowledge_list;
              chatHistoryRef.current.push(lastItem)
              setChatHistory(chatHistoryRef.current);
            }
            

我们看下上面的2块代码,B代码是有Bug,会造成页面不会渲染;

原因如下

第一种方法创建了 chatHistory 的新副本并使用 setChatHistory 更新状态,这种做法更符合React的不可变性原则。第二种方法直接修改了 chatHistoryRef.current 的内容,这可能导致不可预期的渲染行为,因为React可能没有检测到引用变化。第一种方法通常是更安全且推荐的做法,以避免隐含的bug和确保组件正确响应状态变化。

所以我们要记住,React的不可变性的原则;因为React内部会检测引用是否变化;

进阶

第一种写法可以用 use-immer 优化吗?

第一种写法可以用 use-immer 来优化。use-immer 提供了一种处理不可变数据的简便方法,允许你写出看似直接修改状态的代码,而实际上它会安全地产生新的不可变状态。这样可以让你的代码更简洁,同时保留React所推崇的不可变性原则。在你的场景中,use-immer 可以简化处理和更新 chatHistory 状态的逻辑。


if (current_knowledge.data.knowledge_base_results.length > 0 && !responseFlux.includes('paint')) {
  knowledge_list = current_knowledge.data.knowledge_base_results;
  let lastItem = chatHistoryRef.current.pop();
  lastItem[2] = knowledge_list;
  const content = [...chatHistoryRef.current, lastItem];
  setChatHistory(content);
}

const [xx,setChatHistory] = useImmer([]);

if (current_knowledge.data.knowledge_base_results.length > 0 && !responseFlux.includes('paint')) {
  const knowledge_list = current_knowledge.data.knowledge_base_results;
  setChatHistory(draft => {
    let lastItem = draft.pop();
    lastItem[2] = knowledge_list;
    draft.push(lastItem);
  });
}