it编程 > 编程语言 > Javascript

React useCallback使用方法详解

13人参与 2025-02-14 Javascript

1. usecallback 基础概念

usecallback 是 react 的一个 hook,用于记忆函数定义,避免在每次渲染时创建新的函数实例。它在需要将回调函数传递给经过优化的子组件时特别有用。 当state变化的时候引起组件重新渲染执行会导致某个方法被反复创建增加内存负担,这个时候可以使用usecallback将该函数进行缓存,只创建一次

1.1 基本语法

const memoizedcallback = usecallback(
  () => {
    dosomething(a, b);
  },
  [a, b], // 依赖项数组
);

同样的当依赖项省略时组件重新渲染都会执行,当依赖项为空数组的时候只有组件初始化的时候会执行一次,数组里有依赖项的时候依赖项发生变化的时候都会缓存一次

1.2 与普通函数的区别

function parentcomponent() {
  const [count, setcount] = usestate(0);

  // ❌ 每次渲染都会创建新的函数实例
  const handleclick = () => {
    console.log('clicked');
  };

  // ✅ 函数实例会被记忆,只在依赖项变化时更新
  const handleclickmemoized = usecallback(() => {
    console.log('clicked');
  }, []); // 空依赖数组,函数永远不会改变

  return <childcomponent onclick={handleclickmemoized} />;
}

2. usecallback 配合 react.memo 使用

2.1 基本示例

// 子组件使用 react.memo 优化
const childcomponent = react.memo(function childcomponent({ onclick }) {
  console.log("childcomponent rendered");
  return <button onclick={onclick}>click me</button>;
});

// 父组件使用 usecallback
function parentcomponent() {
  const [count, setcount] = usestate(0);
  const [text, settext] = usestate("");

  // 使用 usecallback 记忆回调函数
  const handleclick = usecallback(() => {
    setcount(c => c + 1);
  }, []); // 空依赖数组,因为不依赖任何值

  return (
    <div>
      <input value={text} onchange={e => settext(e.target.value)} />
      <p>count: {count}</p>
      <childcomponent onclick={handleclick} />
    </div>
  );
}

2.2 带有依赖项的示例

function searchcomponent({ onsearch }) {
  const [searchterm, setsearchterm] = usestate("");
  const [searchhistory, setsearchhistory] = usestate([]);

  // 使用 usecallback 记忆搜索函数
  const handlesearch = usecallback(() => {
    if (searchterm.trim()) {
      onsearch(searchterm);
      setsearchhistory(prev => [...prev, searchterm]);
    }
  }, [searchterm, onsearch]); // 依赖 searchterm 和 onsearch

  return (
    <div>
      <input
        value={searchterm}
        onchange={e => setsearchterm(e.target.value)}
      />
      <searchbutton onclick={handlesearch} />
      <searchhistory items={searchhistory} />
    </div>
  );
}

// 优化的子组件
const searchbutton = react.memo(function searchbutton({ onclick }) {
  console.log("searchbutton rendered");
  return <button onclick={onclick}>搜索</button>;
});

const searchhistory = react.memo(function searchhistory({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
});

3. 实际应用场景

3.1 表单处理

function complexform() {
  const [formdata, setformdata] = usestate({
    name: '',
    email: '',
    message: ''
  });

  // 记忆表单字段更新函数
  const handlefieldchange = usecallback((fieldname) => (event) => {
    setformdata(prev => ({
      ...prev,
      [fieldname]: event.target.value
    }));
  }, []); // 不需要依赖项,因为使用了函数式更新

  return (
    <form>
      <formfield
        label="name"
        value={formdata.name}
        onchange={handlefieldchange('name')}
      />
      <formfield
        label="email"
        value={formdata.email}
        onchange={handlefieldchange('email')}
      />
      <formfield
        label="message"
        value={formdata.message}
        onchange={handlefieldchange('message')}
      />
    </form>
  );
}

const formfield = react.memo(function formfield({ label, value, onchange }) {
  console.log(`${label} field rendered`);
  return (
    <div>
      <label>{label}</label>
      <input value={value} onchange={onchange} />
    </div>
  );
});

3.2 列表渲染优化

function todolist() {
  const [todos, settodos] = usestate([]);

  // 记忆添加任务函数
  const handleadd = usecallback((text) => {
    settodos(prev => [...prev, { id: date.now(), text, completed: false }]);
  }, []);

  // 记忆切换完成状态函数
  const handletoggle = usecallback((id) => {
    settodos(prev =>
      prev.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  }, []);

  // 记忆删除函数
  const handledelete = usecallback((id) => {
    settodos(prev => prev.filter(todo => todo.id !== id));
  }, []);

  return (
    <div>
      <addtodo onadd={handleadd} />
      {todos.map(todo => (
        <todoitem
          key={todo.id}
          todo={todo}
          ontoggle={handletoggle}
          ondelete={handledelete}
        />
      ))}
    </div>
  );
}

const todoitem = react.memo(function todoitem({ todo, ontoggle, ondelete }) {
  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onchange={() => ontoggle(todo.id)}
      />
      <span style={{ textdecoration: todo.completed ? 'line-through' : 'none' }}>
        {todo.text}
      </span>
      <button onclick={() => ondelete(todo.id)}>删除</button>
    </div>
  );
});

4. 性能优化最佳实践

4.1 合理使用依赖项

function userprofile({ userid, onupdate }) {
  // ✅ 只在 userid 或 onupdate 变化时更新
  const handleupdate = usecallback(() => {
    onupdate(userid);
  }, [userid, onupdate]);

  // ❌ 不必要的依赖项
  const handleclick = usecallback(() => {
    console.log('clicked');
  }, [userid]); // userid 不需要作为依赖项
}

4.2 避免过度优化

// ❌ 简单组件不需要使用 usecallback
function simplebutton({ onclick }) {
  return <button onclick={onclick}>click me</button>;
}

// ✅ 复杂组件或频繁重渲染的组件使用 usecallback
const complexcomponent = react.memo(function complexcomponent({ onaction }) {
  // 复杂的渲染逻辑
  return (
    // ...
  );
});

5. usecallback 与其他 hooks 配合

5.1 配合 useeffect 使用

function datafetcher({ query }) {
  const [data, setdata] = usestate(null);

  // 记忆获取数据的函数
  const fetchdata = usecallback(async () => {
    const response = await fetch(`/api/search?q=${query}`);
    const result = await response.json();
    setdata(result);
  }, [query]);

  // 在 effect 中使用记忆的函数
  useeffect(() => {
    fetchdata();
  }, [fetchdata]); // fetchdata 作为依赖项

  return <div>{/* 渲染数据 */}</div>;
}

5.2 配合 usememo 使用

function dataprocessor({ data, onprocess }) {
  // 记忆处理函数
  const processdata = usecallback((item) => {
    // 复杂的数据处理逻辑
    return someexpensiveoperation(item);
  }, []);

  // 使用记忆的函数处理数据
  const processeddata = usememo(() => {
    return data.map(processdata);
  }, [data, processdata]);

  return (
    <div>
      {processeddata.map(item => (
        <processeditem
          key={item.id}
          item={item}
          onprocess={onprocess}
        />
      ))}
    </div>
  );
}

6. 注意事项

避免过度使用

正确设置依赖项

配合 react.memo 使用

考虑使用场景

通过合理使用 usecallback 和 react.memo,我们可以有效优化 react 应用的性能。但要记住,过度优化可能会适得其反,应该在实际需要时才进行优化。

到此这篇关于react usecallback使用方法详解的文章就介绍到这了,更多相关react usecallback内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

React类组件更新的底层逻辑案例详解

02-14

前端日历插件VCalendar的简单使用方法

02-14

如何使用 electron-forge 搭建 React + Ts 的项目

02-14

ES6之Proxy的使用详解

02-14

前端jQuery复制文本到剪贴板功能实现

02-14

JavaScripts数组里的对象排序的24个方法(最新整理收藏)

02-14

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论