001package react4j.dom; 002 003import arez.Arez; 004import arez.ArezContext; 005import javax.annotation.Nonnull; 006import javax.annotation.Nullable; 007import jsinterop.annotations.JsFunction; 008import jsinterop.annotations.JsMethod; 009import jsinterop.annotations.JsOverlay; 010import jsinterop.annotations.JsPackage; 011import jsinterop.annotations.JsType; 012import react4j.React; 013import react4j.ReactElement; 014import react4j.ReactNode; 015 016/** 017 * Core interface into React DOM library. 018 */ 019@JsType( isNative = true, namespace = JsPackage.GLOBAL ) 020public class ReactDOM 021{ 022 private ReactDOM() 023 { 024 } 025 026 /** 027 * Interface for performing an action inside batch. 028 */ 029 @FunctionalInterface 030 @JsFunction 031 public interface BatchedUpdatesFn 032 { 033 /** 034 * Perform action while batching react changes. 035 * 036 * @throws Throwable if an error occurred. 037 */ 038 void call() 039 throws Throwable; 040 } 041 042 /** 043 * Interface for performing an action on render complete. 044 */ 045 @FunctionalInterface 046 @JsFunction 047 public interface RenderCallbackFn 048 { 049 /** 050 * Perform action on render complete. 051 */ 052 void call(); 053 } 054 055 @JsOverlay 056 @Nonnull 057 public static ReactRoot createRoot( @Nonnull final Object container ) 058 { 059 return unstable_createRoot( container ); 060 } 061 062 @Nonnull 063 private static native ReactRoot unstable_createRoot( @Nonnull Object container ); 064 065 /** 066 * Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy 067 * of the parent component. 068 * 069 * <p>Even though a portal can be anywhere in the DOM tree, it behaves like a normal React child in every 070 * other way. Features like context work exactly the same regardless of whether the child is a portal, as 071 * the portal still exists in the React tree regardless of position in the DOM tree.</p> 072 * 073 * <p>This includes event bubbling. An event fired from inside a portal will propagate to ancestors in 074 * the containing React tree, even if those elements are not ancestors in the DOM tree.</p> 075 * 076 * @param children the react node to render. 077 * @param container the DOM element to render into. 078 * @return the new portal. 079 */ 080 public static native ReactPortal createPortal( @Nonnull ReactNode children, @Nonnull Object container ); 081 082 /** 083 * Render a React element into the DOM in the supplied container. 084 * 085 * <p>If the React element was previously rendered into container, this will perform an update on it and only 086 * mutate the DOM as necessary to reflect the latest React element.</p> 087 * 088 * <p>If the optional callback is provided, it will be executed after the component is rendered or updated.</p> 089 * 090 * @param node the react node to render. 091 * @param container the DOM element to render into. 092 * @param onUpdate the callback invoked when rendering is complete. 093 * @return a reference to the created React Component, DOM Node, Portal or null (stateless components). 094 */ 095 @Nullable 096 @JsOverlay 097 public static Object render( @Nonnull final ReactNode node, 098 @Nonnull final Object container, 099 @Nullable final RenderCallbackFn onUpdate ) 100 { 101 return _render( React.shouldCheckInvariants() ? ReactElement.createStrictMode( node ) : node, container, onUpdate ); 102 } 103 104 @Nullable 105 @JsMethod( name = "render" ) 106 private static native Object _render( @Nonnull ReactNode node, 107 @Nonnull Object container, 108 @Nullable RenderCallbackFn onUpdate ); 109 110 /** 111 * Render a React element into the DOM in the supplied container. 112 * 113 * <p>If the React element was previously rendered into container, this will perform an update on it and only 114 * mutate the DOM as necessary to reflect the latest React element.</p> 115 * 116 * @param node the react node to render. 117 * @param container the DOM element to render into. 118 * @return a reference to the created React Component, DOM Node, Portal or null (stateless components). 119 * @see #render(ReactNode, Object, RenderCallbackFn) 120 */ 121 @Nullable 122 @JsOverlay 123 public static Object render( @Nonnull ReactNode node, @Nonnull Object container ) 124 { 125 return render( node, container, null ); 126 } 127 128 /** 129 * Remove a mounted React component from the DOM and clean up its event handlers and state. If 130 * no component was mounted in the container, calling this function does nothing. 131 * 132 * @param container the DOM container containing the react component to unmount 133 * @return true if a component was unmounted and false if there was no component to unmount. 134 */ 135 public static native boolean unmountComponentAtNode( @Nonnull Object container ); 136 137 /** 138 * Batch all state updates within the action. 139 * This is currently an unstable API within the React 16, mostly because it is only useful when called 140 * outside an event handler (i.e. from network code) and because it is likely to be enabled by default 141 * in a later version of React. 142 * 143 * @param action the action where all state updates are batched. 144 */ 145 @JsOverlay 146 public static void batchedUpdates( @Nonnull final BatchedUpdatesFn action ) 147 { 148 unstable_batchedUpdates( action ); 149 } 150 151 /** 152 * Register an task interceptor on the current Arez context that ensures any view updates are batched. 153 */ 154 @JsOverlay 155 public static void registerBatchedArezTaskInterceptor() 156 { 157 registerBatchedArezTaskInterceptor( Arez.context() ); 158 } 159 160 /** 161 * Register an task interceptor that ensures any view updates are batched. 162 * 163 * @param context the context to add interceptor to. 164 */ 165 @JsOverlay 166 public static void registerBatchedArezTaskInterceptor( @Nonnull final ArezContext context ) 167 { 168 context.setTaskInterceptor( new BatchingTaskInterceptor() ); 169 } 170 171 /** 172 * The native method with the unstable prefix. 173 * 174 * @param action the action where all state updates are batched. 175 */ 176 @JsMethod 177 private static native void unstable_batchedUpdates( @Nonnull BatchedUpdatesFn action ); 178}