Frequently Asked Questions (FAQ)

❓ How to Store Unproxied State in Reactive Proxied Store

You can achieve this by using ref. This is particularly useful when you want to nest an object within the proxy that is not wrapped by the internal proxy (such as storing DOM elements, File objects, and other unstructured data). However, please note that its changes will not be tracked. For more details and considerations, please refer to ref.

❓ When State is Passed to <input />, Input May Be Interrupted

By default, when the state changes, changes are notified asynchronously to achieve a merged update (i.e., batching) effect, optimizing rendering.

If you want to disable it (for example, when used by an <input /> element, it may conflict with the input method's Composition events), you can set the sync option to true when using store.useSnapshot to notify changes synchronously, avoiding this problem.

1const store = create({ inputValue: '' })
2
3const updateInputValue = (value: string) => {
4  store.mutate.inputValue = value
5}
6
7function App() {
8  const inputValue = store.useSnapshot((s) => s.inputValue, { sync: true })
9
10  return (
11    <input
12      value={inputValue}
13      onChange={(e) => {
14        updateInputValue(e.target.value)
15      }}
16    />
17  )
18}

❓ When Handling Extremely Large Datasets (Typically Tens of Millions of Reads or More), Noticeable Lags Occur

In the vast majority of use cases, you are unlikely to encounter performance bottlenecks. However, when dealing with extremely large datasets (with tens of millions of read operations or more), performance issues may become a problem. This is mainly because, when using Proxy, every data access triggers the proxy's Getter method, thereby causing a significant performance overhead during a large number of read operations. To avoid performance issues with extremely large datasets, consider the following solutions:

  • Use useState: Manage large datasets that don't require reactive features separately using hooks like useState.
  • Use ref to wrap: Wrap large datasets with ref to prevent them from being proxied by Proxy.

You can feel this performance difference intuitively by running the following code in the console:

const obj = { name: 'Reactive' };
const proxiedObj = new Proxy(obj, {});

console.time('Normal Object Get');
for(let i = 0; i < 100_000_000; i++) obj.name;
console.timeEnd('Normal Object Get'); // ~50ms, Chrome 131, MacBook Pro (M1 Pro + 16G)

console.time('Proxied Object Get');
for(let i = 0; i = 100_000_000; i++) proxiedObj.name;
console.timeEnd('Proxied Object Get'); // ~1000ms, Chrome 131, MacBook Pro (M1 Pro + 16G)