[web] Update ContentLoader class name.

This commit is contained in:
Matthew Shao 2017-06-12 08:41:40 +08:00
parent d1a40def20
commit 49a04e37c3
2 changed files with 90 additions and 89 deletions

View File

@ -1,12 +1,11 @@
import React from 'react' import React from 'react'
import renderer from 'react-test-renderer' import renderer from 'react-test-renderer'
import ContentLoaderGenerator from '../../../components/ContentView/ContentLoader' import withContentLoader from '../../../components/ContentView/ContentLoader'
import { TFlow } from '../../ducks/tutils' import { TFlow } from '../../ducks/tutils'
import TestUtils from 'react-dom/test-utils' import TestUtils from 'react-dom/test-utils'
import mockXMLHttpRequest from 'mock-xmlhttprequest' import mockXMLHttpRequest from 'mock-xmlhttprequest'
global.XMLHttpRequest = mockXMLHttpRequest global.XMLHttpRequest = mockXMLHttpRequest
class tComponent extends React.Component { class tComponent extends React.Component {
constructor(props, context){ constructor(props, context){
super(props, context) super(props, context)
@ -17,7 +16,7 @@ class tComponent extends React.Component {
} }
let tflow = new TFlow(), let tflow = new TFlow(),
ContentLoader = ContentLoaderGenerator(tComponent) ContentLoader = withContentLoader(tComponent)
describe('ContentLoader Component', () => { describe('ContentLoader Component', () => {
it('should render correctly', () => { it('should render correctly', () => {

View File

@ -2,98 +2,100 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { MessageUtils } from '../../flow/utils.js' import { MessageUtils } from '../../flow/utils.js'
export default View => class extends React.Component { export default function withContentLoader(View) {
static displayName = View.displayName || View.name return class extends React.Component {
static matches = View.matches static displayName = View.displayName || View.name
static matches = View.matches
static propTypes = { static propTypes = {
...View.propTypes, ...View.propTypes,
content: PropTypes.string, // mark as non-required content: PropTypes.string, // mark as non-required
flow: PropTypes.object.isRequired, flow: PropTypes.object.isRequired,
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
}
constructor(props) {
super(props)
this.state = {
content: undefined,
request: undefined,
}
}
componentWillMount() {
this.updateContent(this.props)
}
componentWillReceiveProps(nextProps) {
if (
nextProps.message.content !== this.props.message.content ||
nextProps.message.contentHash !== this.props.message.contentHash ||
nextProps.contentView !== this.props.contentView
) {
this.updateContent(nextProps)
}
}
componentWillUnmount() {
if (this.state.request) {
this.state.request.abort()
}
}
updateContent(props) {
if (this.state.request) {
this.state.request.abort()
}
// We have a few special cases where we do not need to make an HTTP request.
if(props.message.content !== undefined) {
return this.setState({request: undefined, content: props.message.content})
}
if(props.message.contentLength === 0 || props.message.contentLength === null){
return this.setState({request: undefined, content: ""})
} }
let requestUrl = MessageUtils.getContentURL(props.flow, props.message, (View.name == 'ViewServer' ? props.contentView : undefined)) constructor(props) {
super(props)
// We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable. this.state = {
let request = new XMLHttpRequest(); content: undefined,
request.addEventListener("load", this.requestComplete.bind(this, request)); request: undefined,
request.addEventListener("error", this.requestFailed.bind(this, request)); }
request.open("GET", requestUrl);
request.send();
this.setState({ request, content: undefined })
}
requestComplete(request, e) {
if (request !== this.state.request) {
return // Stale request
} }
this.setState({
content: request.responseText,
request: undefined
})
}
requestFailed(request, e) { componentWillMount() {
if (request !== this.state.request) { this.updateContent(this.props)
return // Stale request
} }
console.error(e)
// FIXME: Better error handling
this.setState({
content: "Error getting content.",
request: undefined
})
}
render() { componentWillReceiveProps(nextProps) {
return this.state.content !== undefined ? ( if (
<View content={this.state.content} {...this.props}/> nextProps.message.content !== this.props.message.content ||
) : ( nextProps.message.contentHash !== this.props.message.contentHash ||
<div className="text-center"> nextProps.contentView !== this.props.contentView
<i className="fa fa-spinner fa-spin"></i> ) {
</div> this.updateContent(nextProps)
) }
}
componentWillUnmount() {
if (this.state.request) {
this.state.request.abort()
}
}
updateContent(props) {
if (this.state.request) {
this.state.request.abort()
}
// We have a few special cases where we do not need to make an HTTP request.
if (props.message.content !== undefined) {
return this.setState({request: undefined, content: props.message.content})
}
if (props.message.contentLength === 0 || props.message.contentLength === null) {
return this.setState({request: undefined, content: ""})
}
let requestUrl = MessageUtils.getContentURL(props.flow, props.message, (View.name == 'ViewServer' ? props.contentView : undefined))
// We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable.
let request = new XMLHttpRequest();
request.addEventListener("load", this.requestComplete.bind(this, request));
request.addEventListener("error", this.requestFailed.bind(this, request));
request.open("GET", requestUrl);
request.send();
this.setState({request, content: undefined})
}
requestComplete(request, e) {
if (request !== this.state.request) {
return // Stale request
}
this.setState({
content: request.responseText,
request: undefined
})
}
requestFailed(request, e) {
if (request !== this.state.request) {
return // Stale request
}
console.error(e)
// FIXME: Better error handling
this.setState({
content: "Error getting content.",
request: undefined
})
}
render() {
return this.state.content !== undefined ? (
<View content={this.state.content} {...this.props}/>
) : (
<div className="text-center">
<i className="fa fa-spinner fa-spin"></i>
</div>
)
}
} }
}; };