继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

React Signals:现代化的状态管理方式

莫回无
关注TA
已关注
手记 194
粉丝 4
获赞 2

React Signals 是一个相对较新的概念,用于简化和优化 React 应用程序的状态管理。借鉴了反应式编程和 SolidJS 或 Angular 等框架的理念,Signals 提供了一种高性能、细粒度的响应机制,专注于减少不必要的重新渲染,从而提升开发者体验。

什么是信号?信号是如何传递信息的?

信号量是一种用于高效跟踪和传播状态变化的响应式基础元素。与 React 的 useStateuseReducer 不同,信号量,

  • 不依赖 React 组件的生命周期。
  • 自动更新依赖这些值的组件或计算,无需额外处理。
  • 避免为了优化而使用 useMemouseCallback 这样的钩子来包裹组件。

主要特点:

  1. 细粒度的反应性:只有直接依赖信号的组件或函数才会被更新。
  2. 独立的生命周期:信号独立于 React 组件,可以在不同上下文中复用。
  3. 可预测的行为:它们通过消除依赖数组,减少错误,从而使状态处理更简单。
为什么在React中使用信号?

如果“Signals”指的是React中的特定概念,请提供更多信息以便更准确地翻译。

性能优化

  • React Signals 允许在细粒度级别上进行更新,这样就可以避免不必要的重新渲染。
  • 特别适合需要频繁或复杂状态更新的应用程序,如仪表板和协作工具。

简化代码

  • 信号比 useStateuseEffect 更少冗余。
  • 效果中的依赖数组和清理逻辑不再需要手动处理这些。

响应式生态系统

  • 与 Angular 或 SolidJS 中的响应性模型类似,信号让 React 能像一个“响应式系统”那样处理状态,从而支持现代开发方式。
如何在 React 中使用状态
1. 安装步骤

尽管目前 React 并不原生支持 React Signals,但你可以借助像 Reactivity 这样的库,或是像 React Forget 这样的实验性框架来实现类似的功能。

运行此命令来安装 @preact/signals 包

npm install @preact/signals

在这个例子中,我们用 @preact/signals 库。

一个基本的例子:计数工具

    import { signal } from '@preact/signals';  

    const Counter = () => {  
      const count = signal(0); // 创建一个信号  

      return (  
        <div>  
          <h1>计数器: {count.value}</h1>  
          <button onClick={() => count.value++}>加一</button>  
          <button onClick={() => count.value--}>减一</button>  
        </div>  
      );  
    };  

    export default Counter;

解释:

  • signal(0) 创建一个初始值为 0 的动态状态变量。
  • count.value 提供信号当前的值,并在信号更新时自动反映新值。
响应式计算

响应式计算允许衍生的状态根据依赖项的变化自动地更新。

    import { signal, computed } from '@preact/signals';

    const App = () => {
      const count = signal(0);
      const double = computed(() => count.value * 2); // 响应式计算

      return (
        <div>
          <h1>计数: {count.value}</h1>
          <h2>双倍: {double.value}</h2>
          <button onClick={() => count.value++}>加一</button>
        </div>
      );
    };

    export default App;

要点:

  • computed 创建一个基于 count.value 的响应式值。
  • 每当 count.value 发生变化时,double.value 会自动随之更新。
带有上下文 API 的信号处理

结合信号数据使用 React 的 Context API 来管理全局状态。

import React, { createContext, useContext } from 'react';
import { signal } from '@preact/signals';

const CountContext = createContext(signal(0));

const CounterProvider = ({ children }: { children: React.ReactNode }) => {
  const count = signal(0);
  return <CountContext.Provider value={count}>{children}</CountContext.Provider>;
};

const Counter = () => {
  const count = useContext(CountContext);

  return (
    <div>
      <h1>当前计数:{count.value}</h1>
      <button onClick={() => count.value++}>加一</button>
    </div>
  );
};

const App = () => (
  <CounterProvider>
    <Counter />
  </CounterProvider>
);

export default App;
高级示例:带有信号的搜索
    import { signal } from '@preact/signals';  

    const searchQuery = signal('');  
    const searchResults = signal<string[]>([]);  

    const fetchResults = async (query: string): {  
      // 模拟 API 请求  
      return ['React', 'Redux', 'Signals'].filter((item) =>  
        item.toLowerCase().includes(query.toLowerCase())  
      );  
    };  

    const SearchComponent = () => {  
      const handleSearch = async () => {  
        searchResults.value = await fetchResults(searchQuery.value);  
      };  

      return (  
        <div>  
          <input  
            type="text"  
            value={searchQuery.value}  
            onChange={(e) => searchQuery.value = e.target.value}  
          />  
          <button onClick={handleSearch}>搜索</button>  
          <ul>  
            {searchResults.value.map((result) => (  
              <li key={result}>{result}</li>  
            ))}  
          </ul>  
        </div>  
      );  
    };  

    export default SearchComponent;

场景

  • 动态搜索功能:信号量会在用户输入查询时动态更新状态。
高级示例:利用信号实现搜索自动完成

信号可以驱动搜索自动完成等响应式组件。

    import React from 'react';  
    import { signal } from '@preact/signals-react';  

    const searchQuery = signal('');  
    const searchResults = signal([]);  

    const fetchResults = async (query) => {  
      // 模拟请求  
      // 'React', 'Redux', 'Signals' 是一些示例搜索结果  
      return ['React', 'Redux', 'Signals'].filter((item) =>  
        item.toLowerCase().includes(query.toLowerCase())  
      );  
    };  

    const Search = () => {  
      const handleSearch = async () => {  
        if (searchQuery.value) {  
          searchResults.value = await fetchResults(searchQuery.value);  
        } else {  
          searchResults.value = [];  
        }  
      };  

      return (  
        <div>  
          <input  
            type="text"  
            value={searchQuery.value}  
            onChange={(e) => (searchQuery.value = e.target.value)}  
            onKeyUp={handleSearch}  
            placeholder="想找什么?"  
          />  
          <ul>  
            {searchResults.value.map((result) => (  
              <li key={result}>{result}</li>  
            ))}  
          </ul>  
        </div>  
      );  
    };  

    // 导出默认的 Search 组件,用于模块化导入  
    export default Search;
带有上下文的信号使用

信号量和 React 的 Context API 结合起来可以很好地管理全局状态。

    import React, { createContext, useContext } from 'react';  
    import { signal } from '@preact/signals-react';  

    const ThemeContext = createContext(signal('light'));  

    const ThemeProvider = ({ children }) => {  
      const theme = signal('light');  
      return (  
        <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>  
      );  
    };  

    const ThemeToggle = () => {  
      const theme = useContext(ThemeContext);  

      return (  
        <button onClick={() => (theme.value = theme.value === 'light' ? 'dark' : 'light')}>  
          切换至 {theme.value === 'light' ? '暗' : '浅'} 模式  
        </button>  
      );  
    };  

    const App = () => (  
      <ThemeProvider>  
        <ThemeToggle />  
      </ThemeProvider>  
    );  

    export default App;
组合信号和派生值

你可以利用计算值来自动生成衍生状态,当依赖变化时会自动更新。

    import React from 'react';  
    import { signal, computed } from '@preact/signals-react';  

    const 计数器 = () => {  
      const count = signal(0);  
      const doubleCount = computed(() => count.value * 2);  

      return (  
        <div>  
          <h1>计数:{count.value}</h1>  
          <h2>双倍:{doubleCount.value}</h2>  
          <button onClick={() => count.value++}>增加</button>  
        </div>  
      );  
    };  

    export default 计数器;
要什么时候使用 React Signals
一些最好的应用场景:
  1. 高度互动的用户界面:仪表板、实时应用、或协作工具。
  2. 精细更新场景:频繁的状态变化仅影响UI部分的场景。
  3. 优化全局状态管理:在更简单的场景下替代Redux或Context API。
避免使用
  • 应用规模较小,使用 useStateuseReducer 就足够了。
  • 如果考虑到生态系统支持或长期维护性,信号在 React 中仍处于实验阶段。
幕后

信号通过依赖追踪来发挥作用:

  1. 信号会跟踪每一个访问其值的功能或组件。
  2. 当信号发生变化时,只会重新执行或重新渲染那些依赖它们的项目。
  3. 跳过了React的虚拟DOM差异计算步骤,转而进行直接更新。

这与 React 重新协调整个虚拟DOM树的过程不同。

结论部分

React Signals 提供了一种现代的方式来处理状态,具有细粒度的响应性和优化的性能。它们减少了代码冗余,提高了代码的可读性,并为管理复杂状态更新提供了处理复杂状态更新的替代方法。随着 React 生态系统的不断发展,signals 可能会成为构建高效和可扩展应用程序的重要组成部分。

下一步:

  • 试试这样的库,如@preact/signals
  • 试试把信号和其他React模式,比如服务器组件或过渡等结合起来。

请我喝杯咖啡买咖啡点

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP