React中的状态管理是开发人员需要解决的问题。 总有一些新库给你选择,而选择合适的库可能是一项困难的工作。

每个现代应用程序都有一个具有状态管理库,并且在选择库时应该考虑很多选项。

我们将使用 valtio 的新的状态管理库,该库用于JavaScript和React应用程序的状态代理。

什么是代理?

代理是计算机软件模式。 代理是一些可以具有自定义行为的对象的包装器。 我们可以代理几乎任何事物,诸如网络连接,对象,文件等。代理以不同的方式工作,但类似与适配器装饰器

代理是由客户端调用的对象包装器,以访问后面的实际服务对象

代理可以帮助开发人员解决现代应用中的重复问题。 它们对于诸如验证,跟踪属性访问,Web服务,监视对象等的情况非常有用。它们是更容易实现对象,更改,测试和重用 。

代理有两个规则:

  • 可控的对象访问
  • 访问对象时,提供额外的功能

自ES6版本以来,我们在JavaScript中有代理。  代理接收两个参数:

  • target  - 要代理的原始对象
  • handler  - 定义对象的操作

这是我们如何使用JavaScript创建代理的方式:

const target = {
  addition: () => 2 + 2,
  subtraction: () => 2 - 2,
};

const handler = {
  get: function(target, prop, receiver) {
    return target;
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.addition()); // 4
console.log(proxy.subtraction()); // 0

代理是一种非常强大的设计模式,用于观察对象并改变它。 它允许我们为对象设计自定义行为。

想象一下如果我们可以在React应用程序中执行此操作。 利用代理处理我们的状态数据。 我们不再需要建立巨大的状态管理库来处理我们所有的状态。

Valtio

Valtio 是一个用于对React和JavaScript应用程序简单的代理状态的库。它是由 poimandres 开源社区创建的。

我们需要做的是包装我们的状态对象,然后我们可以在我们的应用程序中的任何地方进行mutate:

import { proxy } from 'valtio'

const state = proxy({ count: 0 });
() => { ++state.count };

valtio有一个名为useProxy的钩子,有助于我们从快照读取。 useProxy钩子只会在组件的状态发生变化时,渲染我们的组件:

const Counter = () => {
  const snapshot = useProxy(state);
  return (
    <div>
      {snapshot.count}
      <button onClick={() => ++state.count}>Add</button>
    </div>
  );
};

Valtio 具有一个非常强大的功能,称为subscribe。 我们可以从任何地方订阅我们的状态并在我们的组件中使用它。

想象一下,我们的代理状态内,我们拥有一个非常复杂的代理状态,具有一堆不同的状态。 我们有一个身份验证的状态,用来了解用户是否验证:

import { proxy } from 'valtio'

const state = proxy({
  authenticated: false,
  settings: { ... },
  filters: { ... },
  ...
});

我们可以使用subscribe 函数订阅我们的状态的特定部分。 subscribe函数接受两个参数,状态和回调。 state是我们想要订阅状态的哪一部分。 callback是一个回调函数,当状态发生了变化时将被触发:

subscribe(state.authenticated, () => console.log('State changed to', state.authenticated));

Valtio还具有称为subscribeKey的函数,像subscribe功能。 subscribeKey将订阅状态代理的原始属性。 只有在指定的属性已更改时才会被触发:

subscribeKey(state.authenticated, () => console.log('Authenticated state changed to', state.authenticated));

valtio 的另一个功能是它可以在vanilla JavaScript应用中使用:

import { proxy, subscribe, snapshot } from 'valtio/vanilla'

const state = proxy({ books: [...], isAuthenticated: false })

subscribe(state, () => {
  console.log('state:')
  const obj = snapshot(state);
})

现在我们知道一点valtio的知识,让我们看看它在实践中的工作原理。 我们将使用 valtio 为状态代理创建一个简单的示例应用程序,以便React中看到它的好处。

入门

我们将使用create-react-app应用:

npx create-react-app simple-state-with-valtio

现在我们将安装 valtio

yarn add valtio

首先,我们将导入proxyuseProxy从Valtio。 proxy函数用于创建新的状态代理。 useProxy函数用于在我们的React组件上创建本地快照,组件将会监听更改:

import { proxy, useProxy } from 'valtio'

现在,我们将创建状态代理。 我们的状态内部有三个属性firstNamelastNameusers

const state = proxy({ firstName: "", lastName: "", users: [{}] })

在我们的组件内,我们将有一个表单,两个输入和一个按钮。 我们将跟踪每个输入的更改,并将其存储在我们的代理状态中。 该按钮将用于提交我们的表单:

const App = () => {
  return (
    <form>
      <input type="text" />
      <input type="text" />
      <button type="submit">Create</button>
    </form>
    );
}

在我们的组件内,我们将使用useProxy钩子创建快照。 此快照将用于从我们的代理状态获取我们的状态数据并在状态更改时更新:

const App = () => {
  const snapshot = useProxy(state, { sync: true });
  return (
    <form>
      <input type="text" />
      <input type="text" />
      <button type="submit">Create</button>
    </form>
  );
}

请注意,我们将第二个参数传递给useProxy函数。 第二个参数是一个对象

现在在我们的输入上,对于每个输入,我们将要将值设置为状态代理并从我们的snapshot中读取值,如下所示:

const App = () => {
  const snapshot = useProxy(state, { sync: true });
return (
    <form>
      <input type="text" value={snapshot.firstName} onChange={(e) => (state.firstName = e.target.value)} />
      <input type="text" value={snapshot.lastName} onChange={(e) => (state.lastName = e.target.value)} />
      <button type="submit">Create</button>
    </form>
  );
}

现在,我们需要创建我们的提交函数来提交我们的表单。 在我们的函数内,我们将创建一个新的用户分组firstNamelastName值并将其推向users数组。 新用户被推到users后,我们希望将firstNamelastName的值更改为空字符串:

const App = () => {
  const snapshot = useProxy(state, { sync: true });
  const handleSubmit = (e: any) => {
    e.preventDefault();
    const newUser = { firstName: state.firstName, lastName: state.lastName };
    state.users.push(newUser);
    state.firstName = "";
    state.lastName = "";
  }
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={snapshot.firstName} onChange={(e) => (state.firstName = e.target.value)} />
      <input type="text" value={snapshot.lastName} onChange={(e) => (state.lastName = e.target.value)} />
      <button type="submit">Create</button>
    </form>
  );
}

我们现在让我们的组件工作得很好。 我们能够使用Valtio管理我们的状态值,并将新用户提交给我们的状态代理。 现在唯一缺少的事情是一种展示我们拥有的用户数量的方法。

我们使用snapshot并映射我们的用户数组到h1元素:

const App = () => {
  const snapshot = useProxy(state, { sync: true });
const handleSubmit = (e: any) => {
    e.preventDefault();
    const newUser = { firstName: state.firstName, lastName: state.lastName };
    state.users.push(newUser);
    state.firstName = "";
    state.lastName = "";
  }
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={snapshot.firstName} onChange={(e) => (state.firstName = e.target.value)} />
      <input type="text" value={snapshot.lastName} onChange={(e) => (state.lastName = e.target.value)} />
      <button type="submit">Create</button>

      <div>
        {snapshot.users.map((user: any) => (<h1>Hello {user.firstName} {user.lastName}</h1>))}
      </div>
    </form>
  );
}

未来valtio库是会成为一个亮点

结论

状态数据对于现代应用至关重要。 Valtio简单,强大,并结合了作出React和JavaScript的Proxy,使得状态数据易于使用和更改。