Skip to content

Releases: sheinsight/reactive

v0.1.1

02 Mar 08:31
2f92ff6
Compare
Choose a tag to compare

v0.1.1 Release Notes

chore: Enhance TypeScript types for existing functions.
chore: Export essential TypeScript types for external reference.

Full Changelog: v0.1.0...v0.1.1

v0.1.0

29 Feb 09:55
2f7e49c
Compare
Choose a tag to compare

v0.1.0 Release Notes

We're excited to announce the release of v0.1.0! This version brings a range of breaking changes, new features, and enhancements that improve the library's performance, scalability, and developer experience. Here's what's new:

Breaking Changes

  • Snapshots: Symbol properties have been removed and Object.freeze has been swapped with Object.preventExtensions to tackle immutability issues.
  • TypeScript: The release package no longer includes hack-remove-readonly.d.ts, making for more consistent TypeScript definitions.
  • DevTools: We've deprecated the devtool option in favor of a new, feature-rich devtools function for a better debugging interface.
// in global type file, such as `global.d.ts` or `typings.d.ts`
- /// <reference path="@shined/reactive/hack-remove-readonly.d.ts" />
import { create, devtools } from '@shined/reactive'

// remove `devtool` option in create function
const store = create({ name: 'Pikachu' })

// now you should use `devtools` function to enable DevTools
devtools(store, { name: 'pikachu' })

New Features

  • State Selector: Take control of React re-renders with the new selector, which allows for more granular rendering optimization backed by robust TypeScript support.
  • Comparison Function: The introduction of isEqual, a tailor-made comparison function defaulting to shallowEqual, helps in managing state changes efficiently.
  • Utilities: The newly added produce utility acts as an alternative to immer's produce, enhancing state immutability handling.
const App = () => {
  // any change in `store.mutate` will trigger re-render
  const state = store.useSnapshot()

  // only changes in `store.mutate.author` will trigger re-render
  const author = store.useSnapshot((s) => s.author)

  // only changes in `store.mutate.someName` and `store.mutate.someAge` will trigger re-render
  const [name, age] = store.useSnapshot((s) => [s.someName, s.someAge])

  // or use object destructuring, same as above
  const { name, age } = store.useSnapshot((s) => ({
    name: s.someName,
    age: s.someAge,
  }))

  // custom `isEqual` function, default to `shallowEqual`
  const state = store.useSnapshot({
    isEqual: (pre, cur) => Object.is(pre, cur),
  })

  // use `isEqual` function with `selector` as first argument
  // in this case, only changes in `store.mutate.count` that is greater than or equal to 2 will trigger re-render
  const count = store.useSnapshot((s) => s.count, { isEqual: (pre, cur) => cur - pre < 2 })

  return <h1>{name}</h1>
}

Enhancements

  • Dependencies: Development dependencies have been cleaned up for an improved project structure, with key updates to vitest and @testing-library/react.
  • Documentation: We've overhauled our README to serve as the single-point-of-reference for library users.
  • Examples: Our examples are now more intuitive and informative, helping developers understand the library's potential uses cases better.

Internal Improvements

  • Codebase: Restructured for enhanced clarity, the codebase is now more modular.
  • Testing: Test coverage has been expanded with new cases, fortifying the assurance in our library's robustness.
  • Environment: We've upgraded to Node.js version 20.x, ensuring compatibility with the latest performance standards.

Export Changes

  • Adjustments have been made to both root and vanilla exports, including new aliases and direct exports for key functionality, while maintaining that ProxyMap & ProxySet are exported but not yet implemented. see here for full exports changes.

For a complete rundown of changes, experimental features, and bug fixes, be sure to check the associated pull request changelog or code diff.

These updates reflect our commitment to delivering a streamlined and powerful state management solution that meets the needs of modern application development. We hope you enjoy the improvements!

v0.0.19

15 Nov 08:42
68733a4
Compare
Choose a tag to compare

Because proxy-compare has some behavior that doesn't match our expectations, temporary masking relies on contrast logic

proxy-compare#65

reactive#15

v0.0.18

07 Nov 06:59
9d498a8
Compare
Choose a tag to compare

Break change

Now , useSnapshot return value is no longer completely new each time. In the unchanged situation, the previous proxy object will be used again.

This means that you can write the following code normally.

import { store } from "./store";

export default function Foo() {

  const snap = store.useSnapshot();

  useEffect(() => {
    console.log(address);
  }, [snap.user.address]);

  return (
    <>
      <h1>{state.name}</h1>
    </>
  );
}

v0.0.17

06 Nov 02:43
a2638b7
Compare
Choose a tag to compare
  • fix hack-remove-readonly.d.ts

v0.0.16

04 Nov 17:44
007b9a9
Compare
Choose a tag to compare

Subscribe store in component

You can listen to store changes in the component, and once the store changes, perform certain operations.

import { store } from "./store";
import { useSubscribe } from "@shined/reactive";

export default function Foo() {
  const snap = store.useSnapshot();

  // Use "original" to obtain the raw data within the snapshot.
  // This data can be applied to the deps of useEffect to avoid infinite execution of useEffect.
  const address = original(snap.user.address);

  useEffect(() => {
    console.log(address);
  }, [address]);

  return (
    <>
      <h1>{state.name}</h1>
    </>
  );
}

deprecated useSubscribe

Because many users find it difficult to control this hooks, they always end up breaking the root node. Therefore, it is deprecated and will be removed in future versions.

v0.0.15

03 Nov 17:25
d26d935
Compare
Choose a tag to compare

Subscribe store in component

You can listen to store changes in the component, and once the store changes, perform certain operations.

import { store } from "./store";
import { useSubscribe } from "@shined/reactive";

export default function Foo() {
  const snap = store.useSnapshot();

  useSubscribe(
    () => {
      // do something when `store.users` changes

      // ❌ Error: You will fall into an infinite loop.
      store.mutate.users = [];
    },
    {
      // watch changes of `store.users`
      // 🤡 deps You must get from store, snap cannot be used as deps for useSubscribe.
      deps: [store.mutate.users],

      // By default, useSubscribe will be executed asynchronously. If you want to execute it synchronously, you can open this configuration option.
      sync: true,
    }
  );

  return (
    <>
      <h1>{state.name}</h1>
    </>
  );
}

v0.0.14

03 Nov 17:02
1b9953f
Compare
Choose a tag to compare

add ref api

A ref is useful in the rare instances you to nest an object in a proxy that is not wrapped in an inner proxy and, therefore, is not tracked.

import { create } from "@shined/reactive";

const store = create({
  users: [{ id: 1, name: "Pikachu", component: ref({ table: null }) }],
});

Once an object is wrapped in a ref, it should be mutated without resetting the object or rewrapping in a new ref.

// do mutate
store.users[0].component.table = document.querySelector("#table");
// do reset
store.users[0].component.table = null;

// don't ❌
store.users[0].component = {};

Typical application scenarios :

You want to share an instance of a component among multiple components in order to call imperative APIs.

Once you use ref to wrap an object, the object will not follow the reactive rendering rules, and reactive will not collect dependencies of that object. At the same time, it will not listen to changes on that object. Therefore, you cannot reassign a ref object but can modify its properties. You also cannot reset it to a non-ref object.

v0.0.13

03 Nov 15:20
44b6b6a
Compare
Choose a tag to compare

🚓🚓🚓

Break Change

With the help of microtasks, we change the default rendering behavior from synchronous to asynchronous.

This allows us to have batch rendering capability in React 16 and 17 as well.

This is a breaking change, but we believe it will not cause significant inconvenience to a large number of users at present.

If you encounter rendering issues with specific components after upgrading, you can use store.useSnapshot({ sync: true }) to resolve them.

v0.0.12

15 Sep 09:42
3c8c98b
Compare
Choose a tag to compare

Better cooperation among various component libraries