Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framework: Get HTTP data #22549

Merged
merged 7 commits into from
May 2, 2018
Merged

Framework: Get HTTP data #22549

merged 7 commits into from
May 2, 2018

Commits on Apr 30, 2018

  1. Framework: Get HTTP data

    Because sometimes we don't want to store a bunch of data and yet we want
    to stick close to the data layer.
    
    The generalized system of handlers in the data layer presents specific
    challenges when React components want transient data and creating
    reducers, data layer handlers, and selectors requires efforts
    disproportionate to the task.
    
    The data layer provides centralized and optimized abstractions over
    network activity but also depends on Redux actions to update app state.
    
    Sometimes we also store a significant amount of data which doesn't
    really need to belong in our Redux state tree as it adds bloat and
    needless garbage collection overhead.
    
    In this patch I'm introducing the `httpData` system as a precursor to a
    more specific `apiData` system which hopes to improve the data layer's
    ability to provide structure without overhead and form a basis for a
    long-necessary generalized request-tracking system.
    
    This system may end up as a prototype for storing application data
    outside of the Redux tree and in a _more proper_ database for its needs.
    For instance, in many cases what we need in state is not th data itself
    but rather whether or not the data has changed since the last dispatch.
    A post object may contain many kilobytes of data but truly "belong" in
    IndexedDB.
    
    The `httpData` system stores nothing in `state` other than a ticker used
    to indicate when there are data updates. If any component is
    `connect()`ed into the Redux store then because `httpData` dispatches a
    tick then `connect()` will run and we have the change to refresh the
    data from the external system. In this case it's a `Map()` and the
    update should be extremely fast.
    
    Data is referenced by a provided `id` and the namespace is flat. The
    `id` should be a string probably and we should standardize formats.
    
    ```js
    // type-id1-id2-id3
    `post-${ siteId }-${ postId }`
    ```
    
    The ids need to be unique to the resource.
    
    Surprisingly we can reference a resource before it has been requested
    due to the consolidation of references with the resource id itself.
    This also opens some other questions due to the fact that different
    requests can provide data to the same id.
    
    It does not matter what kind of request `httpData()` tracks. It merely
    passes on the `fetch` property of the action into the dispatcher.
    In most cases this will be a WordPress.com API request with the `http()`
    helper but it could also be a raw HTTP request with the raw helper.
    An optional `fromApi` function can be provided to parse and transform
    the HTTP response.
    
    Currently the data pool will not be cleared and will continu to
    accumulate as the application runs. As we discover need we should be
    able to easily enhance the middleware with a pruning routine to clear
    out old data. If a component is rendering data which would be cleared
    then we would fire another tick and the component could decide to
    re-issue another request to update the data.
    
    Freshness can be maintained through examining the metadata and we could
    easily add a flag if we felt it was warranted.
    
    ```js
    componentDidUpdate() {
    	const { postId, postIsStale, requestPost, siteId } = this.props;
    
    	if ( postIsStale ) {
    		requestPost( siteId, postId );
    	}
    }
    
    const mapStateToProps = ( state, { postId } ) => {
    	const siteId = getSelectedSiteId( state );
    	const post = getHttpData( `post-${ siteId }-${ postId }` );
    	const isPending = post.status === 'pending';
    	const postAge = Date.now9) - post.lastUpdated;
    
    	return {
    		siteId: getSelectedSiteId( state ),
    		post: post.data,
    		postIsStale: ! isPending && postAge < 5 * MINUTE_IN_MS,
    	}
    };
    
    const mapDispatchToProps = ( {
    	requestPost: ( siteId, postId ) => requestHttpData(
    		`post-${ siteId }-${ postId }`,
    		requestSitePost( siteId, postId )
    	),
    } )
    ```
    
    This should not replace commonly-used and well-defined data types and
    their data-layer handlers. It's more for one-off requests and transient
    data. The example is there only for illustrative purposes.
    dmsnell committed Apr 30, 2018
    Configuration menu
    Copy the full SHA
    19376eb View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    4cd80e6 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    7b75ac4 View commit details
    Browse the repository at this point in the history
  4. Refine parseResponse

    dmsnell committed Apr 30, 2018
    Configuration menu
    Copy the full SHA
    afc7179 View commit details
    Browse the repository at this point in the history
  5. Add store enhancer

    dmsnell committed Apr 30, 2018
    Configuration menu
    Copy the full SHA
    be3f7e5 View commit details
    Browse the repository at this point in the history
  6. Fix store enhancer

    dmsnell committed Apr 30, 2018
    Configuration menu
    Copy the full SHA
    7bb69da View commit details
    Browse the repository at this point in the history
  7. fix things

    dmsnell committed Apr 30, 2018
    Configuration menu
    Copy the full SHA
    6a0bb2d View commit details
    Browse the repository at this point in the history