Skip to content

Commit

Permalink
[Blocks] Initial implementation of cache and data/fetch (facebook#18774)
Browse files Browse the repository at this point in the history
* Rename ReactCache -> ReactCacheOld

We still use it in some tests so I'm going to leave it for now. I'll start making the new one in parallel in the react package.

* Add react/unstable-cache entry point

* Add react-data entry point

* Initial implementation of cache and data/fetch

* Address review
  • Loading branch information
gaearon committed Apr 29, 2020
1 parent 53d68b3 commit 5153267
Show file tree
Hide file tree
Showing 25 changed files with 367 additions and 98 deletions.
3 changes: 2 additions & 1 deletion fixtures/blocks/src/App.js
Expand Up @@ -7,9 +7,10 @@

import React, {useReducer, useTransition, Suspense} from 'react';
import loadPost from './Post';
import {createCache, CacheProvider} from './lib/cache';
import {createCache, CacheProvider} from 'react/unstable-cache';

const initialState = {
// TODO: use this for invalidation.
cache: createCache(),
params: {id: 1},
RootBlock: loadPost({id: 1}),
Expand Down
6 changes: 4 additions & 2 deletions fixtures/blocks/src/Comments.js
Expand Up @@ -6,11 +6,13 @@
*/

import * as React from 'react';
import {fetch} from './lib/data';
import {fetch} from 'react-data/fetch';

function load(postId) {
return {
comments: fetch('http://localhost:3001/comments?postId=' + postId),
comments: JSON.parse(
fetch('http://localhost:3001/comments?postId=' + postId)
),
};
}

Expand Down
4 changes: 2 additions & 2 deletions fixtures/blocks/src/Post.js
Expand Up @@ -7,12 +7,12 @@

import * as React from 'react';
import {block, Suspense} from 'react';
import {fetch} from './lib/data';
import {fetch} from 'react-data/fetch';
import loadComments from './Comments';

function load(params) {
return {
post: fetch('http://localhost:3001/posts/' + params.id),
post: JSON.parse(fetch('http://localhost:3001/posts/' + params.id)),
Comments: loadComments(params.id),
};
}
Expand Down
30 changes: 0 additions & 30 deletions fixtures/blocks/src/lib/cache.js

This file was deleted.

59 changes: 0 additions & 59 deletions fixtures/blocks/src/lib/data.js

This file was deleted.

2 changes: 1 addition & 1 deletion packages/react-cache/index.js
Expand Up @@ -9,4 +9,4 @@

'use strict';

export * from './src/ReactCache';
export * from './src/ReactCacheOld';
File renamed without changes.
12 changes: 12 additions & 0 deletions packages/react-data/README.md
@@ -0,0 +1,12 @@
# react-data

This package is meant to be used alongside yet-to-be-released, experimental React features. It's unlikely to be useful in any other context.

**Do not use in a real application.** We're publishing this early for
demonstration purposes.

**Use it at your own risk.**

# No, Really, It Is Unstable

The API ~~may~~ will change wildly between versions.
12 changes: 12 additions & 0 deletions packages/react-data/fetch.js
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

export * from './src/fetch/ReactDataFetch';
12 changes: 12 additions & 0 deletions packages/react-data/index.js
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

export * from './src/ReactData';
7 changes: 7 additions & 0 deletions packages/react-data/npm/fetch.js
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-data-fetch.production.min.js');
} else {
module.exports = require('./cjs/react-data-fetch.development.js');
}
7 changes: 7 additions & 0 deletions packages/react-data/npm/index.js
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-data.production.min.js');
} else {
module.exports = require('./cjs/react-data.development.js');
}
22 changes: 22 additions & 0 deletions packages/react-data/package.json
@@ -0,0 +1,22 @@
{
"private": true,
"name": "react-data",
"description": "Helpers for creating React data sources",
"version": "0.0.0",
"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-data"
},
"files": [
"LICENSE",
"README.md",
"build-info.json",
"index.js",
"fetch.js",
"cjs/"
],
"peerDependencies": {
"react": "^16.13.1"
}
}
12 changes: 12 additions & 0 deletions packages/react-data/src/ReactData.js
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export function createResource(): any {
// TODO
}
23 changes: 23 additions & 0 deletions packages/react-data/src/__tests__/ReactData-test.js
@@ -0,0 +1,23 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/

'use strict';

describe('ReactData', () => {
let ReactData;

beforeEach(() => {
ReactData = require('react-data');
});

// TODO: test something useful.
it('exports something', () => {
expect(ReactData.createResource).not.toBe(undefined);
});
});
23 changes: 23 additions & 0 deletions packages/react-data/src/__tests__/ReactDataFetch-test.js
@@ -0,0 +1,23 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/

'use strict';

describe('ReactDataFetch', () => {
let ReactDataFetch;

beforeEach(() => {
ReactDataFetch = require('react-data/fetch');
});

// TODO: test something useful.
it('exports something', () => {
expect(ReactDataFetch.fetch).not.toBe(undefined);
});
});
93 changes: 93 additions & 0 deletions packages/react-data/src/fetch/ReactDataFetch.js
@@ -0,0 +1,93 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {Wakeable} from 'shared/ReactTypes';

import {readCache} from 'react/unstable-cache';

const Pending = 0;
const Resolved = 1;
const Rejected = 2;

type PendingResult = {|
status: 0,
value: Wakeable,
|};

type ResolvedResult = {|
status: 1,
value: mixed,
|};

type RejectedResult = {|
status: 2,
value: mixed,
|};

type Result = PendingResult | ResolvedResult | RejectedResult;

const fetchKey = {};

function readResultMap(): Map<string, Result> {
const resources = readCache().resources;
let map = resources.get(fetchKey);
if (map === undefined) {
map = new Map();
resources.set(fetchKey, map);
}
return map;
}

// TODO: options, auth, etc.
export function fetch(url: string): Object {
const map = readResultMap();
const entry = map.get(url);
if (entry === undefined) {
let resolve = () => {};
const wakeable: Wakeable = new Promise(r => {
// TODO: should this be a plain thenable instead?
resolve = r;
});
const result: Result = {
status: Pending,
value: wakeable,
};
map.set(url, result);
const xhr = new XMLHttpRequest();
xhr.onload = function() {
// TODO: should we handle status codes?
if (result.status !== Pending) {
return;
}
const resolvedResult = ((result: any): ResolvedResult);
resolvedResult.status = Resolved;
resolvedResult.value = xhr.response;
resolve();
};
xhr.onerror = function() {
if (result.status !== Pending) {
return;
}
const rejectedResult = ((result: any): RejectedResult);
rejectedResult.status = Rejected;
// TODO: use something else as the error value?
rejectedResult.value = xhr;
resolve();
};
xhr.open('GET', url);
xhr.send();
throw wakeable;
}
const result: Result = entry;
if (result.status === Resolved) {
return result.value;
} else {
throw result.value;
}
}
7 changes: 7 additions & 0 deletions packages/react/npm/unstable-cache.js
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-unstable-cache.production.min.js');
} else {
module.exports = require('./cjs/react-unstable-cache.development.js');
}
3 changes: 2 additions & 1 deletion packages/react/package.json
Expand Up @@ -16,7 +16,8 @@
"cjs/",
"umd/",
"jsx-runtime.js",
"jsx-dev-runtime.js"
"jsx-dev-runtime.js",
"unstable-cache.js"
],
"main": "index.js",
"repository": {
Expand Down

0 comments on commit 5153267

Please sign in to comment.