Skip to main content

v0.13: NextJS App Router, Expo, React 19, Redux

· 7 min read
Nathaniel Tucker
Creator of Reactive Data Client

Platforms:

Packages moved inside @data-client/react:

  • Redux
  • Hooks

Other Improvements

Breaking Changes:

note

Version 0.12 was skipped due to a publishing mishap.

Platforms

NextJS App Router

NextJS 12 includes a new way of routing in the '/app' directory. This allows further performance improvements, as well as dynamic and nested routing. This makes NextJS a viable platform to build rich dynamic applications, rather than just static websites.

While other fetching methods require slow client-side fetching; Reactive Data Client provides the best of both SPA and MPA. #3074, #3093

Like MPAs, SSR with Data Client means the fastest possible initial page load. Like SPAs, Data Client offers faster navigation, client side mutations, and remote-driven mutations (like websockets) than MPAs.

Additionally, Data Client with SSR still provides the performance advantages over other client-side fetching libraries.

Data Client performs streaming SSR of the HTML, streamlining the initial application load experience. Uniquely, Data Client is then immediately interactive with 0 client side fetches. This is achieved by initializing the Client Store with normalized data during the SSR phase.

Usage

Render DataProvider from the /nextjs entrypoint in your root layout.

app/layout.tsx
import { DataProvider } from '@data-client/react/nextjs';
import { AsyncBoundary } from '@data-client/react';

export default function RootLayout({ children }) {
return (
<html>
<body>
<DataProvider>
<header>Title</header>
<AsyncBoundary>{children}</AsyncBoundary>
<footer></footer>
</DataProvider>
</body>
</html>
);
}

Full NextJS Guide

Mutations demo

More Demos

Live data demo

Other SSR

Add /ssr entrypoint - eliminating the need for @data-client/ssr package completely d1b9e96

Before
import {
createPersistedStore,
createServerDataComponent,
} from '@data-client/ssr';
After
import {
createPersistedStore,
createServerDataComponent,
} from '@data-client/react/ssr';

This makes it possible to easily integrate Data Client into any SSR framework. We welcome contributions for integration with any open source framework.

Expo

We have begun work on Expo/ExpoGo demos, and thus found and fixed some compatibility issues by these integrations. Please report any issues that we may have missed.

React 19

We now support React 19. #3071

This required dropping support for versions less than 16.14, as we must use the jsx runtime exported from React itself. This has the added benefit of reducing the bundle size.

Redux

Add @data-client/react/redux #3099. This removes the need for the separate @data-client/redux package.

Before
import {
ExternalDataProvider,
PromiseifyMiddleware,
applyManager,
initialState,
createReducer,
prepareStore,
} from '@data-client/redux';
After
import {
ExternalDataProvider,
PromiseifyMiddleware,
applyManager,
initialState,
createReducer,
prepareStore,
} from '@data-client/react/redux';

Add middlewares argument to prepareStore() #3099

const { store, selector, controller } = prepareStore(
initialState,
managers,
Controller,
otherReducers,
extraMiddlewares,
);

controller.set()

controller.set() updates any Queryable Schema. #3105, #3129

ctrl.set(
Todo,
{ id: '5' },
{ id: '5', title: 'tell me friends how great Data Client is' },
);

Functions can be used in the value when derived data is used. This prevents race conditions.

const id = '2';
ctrl.set(Article, { id }, article => ({ id, votes: article.votes + 1 }));
note

The response must include values sufficient to compute Entity.pk()

This makes it more straightforward to manipulate the store with Managers. For example we can directly set our Ticker entity when receiving websocket messages:

More Demos

Type improvements

REST changes

path strings

Support + and * and {} in RestEndpoint.path. a6b4f4a

const getThing = new RestEndpoint({
path: '/:attr1?{-:attr2}?{-:attr3}?',
});

getThing({ attr1: 'hi' });
getThing({ attr2: 'hi' });
getThing({ attr3: 'hi' });
getThing({ attr1: 'hi', attr3: 'ho' });
getThing({ attr2: 'hi', attr3: 'ho' });

ctrl.fetch() and Unions

Unions values in ctrl.fetch() return value are now an instance of their Entity class. #3063

import { getFeed } from './Feed';

function useFeedHandler() {
  const ctrl = useController();

  const handleSomething = async () => {
    const feed = await ctrl.fetch(getFeed);
    return feed.map(item => {
      if (item.type == 'link') {
        // we can use class defined getter
        return item.anchor;
      }
    });
  }
  return handleSomething;
}

Migration guide

This upgrade requires updating all package versions simultaneously.

npm install --save @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0

actionTypes.SET_TYPE -> actionTypes.SET_RESPONSE_TYPE

If you wrote a custom Manager that handled actionTypes.SET_TYPE, you'll need to rename it actionTypes.SET_RESPONSE_TYPE.

Before
import type { Manager, Middleware } from '@data-client/react';
import { actionTypes } from '@data-client/react';

export default class LoggingManager implements Manager {
middleware: Middleware = controller => next => async action => {
switch (action.type) {
case actionTypes.SET_TYPE:
console.info(
`${action.endpoint.name} ${JSON.stringify(action.response)}`,
);
return next(action);
// actions must be explicitly passed to next middleware
default:
return next(action);
}
};

cleanup() {}
}
After
import type { Manager, Middleware } from '@data-client/react';
import { actionTypes } from '@data-client/react';

export default class LoggingManager implements Manager {
middleware: Middleware = controller => next => async action => {
switch (action.type) {
case actionTypes.SET_RESPONSE_TYPE:
console.info(
`${action.endpoint.name} ${JSON.stringify(action.response)}`,
);
return next(action);
// actions must be explicitly passed to next middleware
default:
return next(action);
}
};

cleanup() {}
}

SetAction -> SetResponseAction

React 16.14+

Changes the minimum React version from 16.8.4 -> 16.14. There are no code updates needed.

CacheProvider -> DataProvider

Move to DataProvider for future version compatibility. It is also exported as CacheProvider so this is not a breaking change. #3095

Before
import { CacheProvider } from '@data-client/react';
import ReactDOM from 'react-dom';

ReactDOM.createRoot(document.body)
.render(
<CacheProvider>
<App />
</CacheProvider>,
);
After
import { DataProvider } from '@data-client/react';
import ReactDOM from 'react-dom';

ReactDOM.createRoot(document.body)
.render(
<DataProvider>
<App />
</DataProvider>,
);

Upgrade support

As usual, if you have any troubles or questions, feel free to join our Chat or file a bug