/** * NOTE: This is a fork of the original ServerSideRenderX component. * You can find more about that project here: https://github.com/dgwyer/server-side-render-x * * Changes: * - some minor clean up was done to remove references to variables which were never actually used. */ /** * External dependencies */ import {isEqual, debounce} from 'lodash'; /** * WordPress dependencies */ const {Component, RawHTML, Fragment} = wp.element; import { __ } from '@wordpress/i18n' const apiFetch = wp.apiFetch; const {addQueryArgs} = wp.url; const {Placeholder} = wp.components; export function rendererPath(block, attributes = null, urlQueryArgs = {}) { return addQueryArgs(`/wp/v2/block-renderer/${block}`, { context: 'edit', ...(null !== attributes ? {attributes} : {}), ...urlQueryArgs, }); } export class ServerSideRenderX extends Component { constructor(props) { super(props); this.state = { response: null, prevResponse: null, }; } componentDidMount() { this.isStillMounted = true; this.fetch(this.props); // Only debounce once the initial fetch occurs to ensure that the first // renders show data as soon as possible. this.fetch = debounce(this.fetch, 500); } componentWillUnmount() { this.isStillMounted = false; } componentDidUpdate(prevProps) { if (!isEqual(prevProps, this.props)) { this.fetch(this.props); } } fetch(props) { if (!this.isStillMounted) { return; } if (null !== this.state.response) { this.setState((state) => ({ response: null, prevResponse: state.response, })); } const {block, attributes = null, urlQueryArgs = {}} = props; const path = rendererPath(block, attributes, urlQueryArgs); // Store the latest fetch request so that when we process it, we can // check if it is the current request, to avoid race conditions on slow networks. const fetchRequest = (this.currentFetchRequest = apiFetch({path}) .then((response) => { if (this.isStillMounted && fetchRequest === this.currentFetchRequest && response) { this.setState({response: response.rendered}); } }) .catch((error) => { if (this.isStillMounted && fetchRequest === this.currentFetchRequest) { this.setState({ response: { error: true, errorMsg: error.message, }, }); } })); return fetchRequest; } render() { const {right, top, unit} = this.props.spinnerLocation; const response = this.state.response; const prevResponse = this.state.prevResponse; let prevResponseHTML = ''; if (prevResponse !== null) { prevResponseHTML = `
${prevResponse}
`; } const { className, EmptyResponsePlaceholder = ({className}) => ( {__('Block rendered as empty.')} ), ErrorResponsePlaceholder = ({response, className}) => { const errorMessage = sprintf( // translators: %s: error message describing the problem __('Error loading block: %s'), response.errorMsg ); return {errorMessage}; }, } = this.props; if (response === '') { return ; } else if (!response) { return ( {prevResponseHTML} ); } else if (response.error) { return ; } return ( {response} ); } } export default ServerSideRenderX;