Giter VIP home page Giter VIP logo

react4j's Introduction

React4j

React4j

Build Status codecov GWT3/J2CL compatible

The goal of this project is to be able to seamlessly use the react component model from GWT and make use of the ecosystem of react development support tooling such a React's Devtools. It would be nice to be able to use existing react component libraries and toolkits from Java but this is not an explicit goal. The project also aims to also develop guards that stop you from using the toolkit incorrectly with no performance cost in production builds.

React4j is under heavy development and sometimes the documentation does not keep up to date. However the goal of the toolkit is to be easy to use and this includes clear and concise documentation. If something is unclear please report it as a bug because it is a bug. If a new user has a bad time then we need to fix the problem.

For more information about React4j, please see the Website. For the source code and project support please visit the GitHub project.

Contributing

React4j was released as open source so others could benefit from the project. We are thankful for any contributions from the community. A Code of Conduct has been put in place and a Contributing document is under development.

License

React4j is licensed under Apache License, Version 2.0.

Credit

  • Stock Software for providing significant support in building and maintaining React4j, particularly at it's inception.

  • This toolkit began as an experiment using gwt-react to build a React/GWT hybrid application. Before too long we merged and forked the gwt-react projects and began to evolve this into a product that fit our needs better. Credit goes to Paul Stockley and other contributors to the gwt-react projects who we based most of our initial work on. Several files within the code-base remain as direct copies from the original gwt-react project.

  • It should go without saying that this toolkit owes it existence to the wonderful ReactJS project.

react4j's People

Contributors

dependabot[bot] avatar github-actions[bot] avatar preid avatar realityforge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

lolaalamal

react4j's Issues

Add the ability to constrain an input ReactNode to a particular type

Downstream applications often create components that are expected to be populated by child components of a specific type. i.e. a SideBar component that should only container SideBarButton child components.

React4j does not currently have any way to enforce this or warn the user when they violate such a constraint. It should be possible to add a constraint such that this is either validated at runtime (via a check that input props have the correct shape) and/or enforced at build time.

This would make several constructs that appear in downstream projects much easier to manage.

@PostDispose without @PreDispose generated broken code

Code to demo:

Overview( @nonnull final GlobalViewService globalViewService,
@nonnull final TopLevelOrgUnitRepository topLevelOrgUnitRepository,
@nonnull final OrgUnitSummaryService orgUnitSummaryService )
{
_globalViewService = Objects.requireNonNull( globalViewService );
_topLevelOrgUnitRepository = Objects.requireNonNull( topLevelOrgUnitRepository );
_orgUnitSummaryService = Objects.requireNonNull( orgUnitSummaryService );
}

@PostDispose
void preDispose()
{
_orgUnitSummaryService.setActive( false );
}
`

Generates:
private Arez_React4j_Overview(@Nonnull final NativeComponent $$react4j$$_nativeComponent, final GlobalViewService globalViewService, final TopLevelOrgUnitRepository topLevelOrgUnitRepository, final OrgUnitSummaryService orgUnitSummaryService) { super($$react4j$$_nativeComponent,globalViewService,topLevelOrgUnitRepository,orgUnitSummaryService); final ArezContext $$arezv$$_context = Arez.context(); final int $$arezv$$_id = ++$$arezi$$_nextId; final String $$arezv$$_name = Arez.areNamesEnabled() ? "Overview." + $$arezv$$_id : null; final Component $$arezv$$_component = Arez.areNativeComponentsEnabled() ? $$arezv$$_context.component( "Overview", $$arezv$$_id, $$arezv$$_name, , () -> super.preDispose() ) : null; this.$$arezi$$_kernel = new ComponentKernel( Arez.areZonesEnabled() ? $$arezv$$_context : null, Arez.areNamesEnabled() ? $$arezv$$_name : null, $$arezv$$_id, Arez.areNativeComponentsEnabled() ? $$arezv$$_component : null, null, Arez.areNativeComponentsEnabled() ? null : this::$$arezi$$_dispose, Arez.areNativeComponentsEnabled() ? null : () -> super.preDispose(), false, false, false ); this.$$arez$$_render = $$arezv$$_context.tracker( Arez.areNativeComponentsEnabled() ? $$arezv$$_component : null, Arez.areNamesEnabled() ? $$arezv$$_name + ".render" : null, () -> super.onRenderDepsChange(), Flags.RUN_LATER | Flags.OBSERVE_LOWER_PRIORITY_DEPENDENCIES | Flags.NO_REPORT_RESULT | Flags.NESTED_ACTIONS_DISALLOWED | Flags.AREZ_OR_NO_DEPENDENCIES | Flags.PRIORITY_LOW ); this.$$arezi$$_kernel.componentConstructed(); this.$$arezi$$_kernel.componentReady(); }

Line in error
final Component $$arezv$$_component = Arez.areNativeComponentsEnabled() ? $$arezv$$_context.component( "Overview", $$arezv$$_id, $$arezv$$_name, , () -> super.preDispose() ) : null;

Note the double , ,

Consider porting other examples to help asses and document react4j

HackerNews clones have been used as an example application in a lot of places. Such an example would use more features than the current TodoMVC example which is rather small. We could use the HackerNews clone as part of our build process and measure code size changes and potentially performance as part of the build.

Possible examples to draw upon:

Remove the requirement to extend react4j.Component

React4j components need to extend react4j.Component and be annotated with react4j.annotations.ReactComponent. This is mostly due to legacy experiments in the early days of react4j.

A better approach would be to add two new annotations:

  • @Render that annotates a method that is invoked to render the component and should appear exactly once within a component.
  • @ScheduleRender(force=true|false) that annotates an abstract method that can be invoked to schedule a render. It should be rarely (never?) used and just replaces existing scheduleRender calls.

After this change, components will no longer need to extend react4j.Component and this class can be removed.

Reorder steps in *Builder so that immutable inputs occur before mutable inputs

It seems reasonable that components should have immutable/key contributing props earlier in the *Builder classes than later. We could do this by reordering the inputs when generating the builder or by detecting the declaration ordering and objecting if it does not follow this convention.

detecting ordering is complex as we would likely want to guarantee an ordering such as

  • source=context, immutable=true
  • source=context, immutable=false
  • source=user, immutable=true
  • source=user, immutable=false

However, we would still need to do this for each level of inheritance hierarchy and this seems complex and overly burdensome on the developers.

Port animation or transition library

Another part that could be supported by a library is a transition or animation library. The simplest approach is to port react-transition-group. The basic idea being that we want to be able to easily use css transitions when components come and go.

For more advanced cases it may be useful to look at importing features from react-move or more likely from react-spring.

If @ActAsComponent is present on type then @Prop.disposeable should default to ENABLE

Arez added the @ActAsComponent annotation which allows Arez to treat a type as a component. We should update the AUTODETECT rule for the @Prop.disposable parameter to use this component so that it can default to ENABLED in that scenario.

We may also want to issue a warning that we have set the value to default if we explicitly set ENABLE. We should be able to suppress this warning with an appropriate @SuppressWarning or @React4jSuppressWarning.

Generate component documentation from component type

The annotations on a component are useful enough to generate some minimal documentation. The documentation could describe the props (i.e. required versus optional, name, type) as well as some basic component documentation (is it reactive, stateful or is it a pure presentation component).

Additional @Doc annotations or javadocs could also describe further information about the component. (i.e. What does prop a prop do, what does the component do). The custom @Doc annotation could also reference examples that can be output in the documentation and/or fed into basic test infrastructure. This ensures that the examples will continue to work as the library is evolved.

There are a few examples like this in react world ... stylguidist??

Port the "hooks-drum-machine" example

The hooks-drum-machine project was used to experiment with the new react hooks API. It would be interesting to see how it compares with react4j. This applications looks like it will challenge react4j in several ways ... and it will be more fun to build than your standard run of the mill data app.

Rebuild the website

We initially had a more useful website but as the framework has evolved the website has either been removed or got out of date. As the evolution of the framework begins to slow down, it would be useful to re-add and reorganize the documentation.

We could use the following sites as inspiration.

It would also be useful to add some diagrams of the component lifecycle such as the one from this tweet or the most excellent image from the article

Demo app is not running (maven)

Hi!
Thank you for this interesting project.

I'm considering building an application with React4J, but at first I tried to run at least one example to see whether it works fine with my environment.

Environment:

Mint Linux 18.3

Relevant code or config:
What happened:
Problem description:
Reproduction repository:

I tried to follow instructions and run examples from here.
I'm interested in Maven, Gradle or Bazel.
Until the last one is ready, I try with the Maven example.
It compiles fine, but when I try to run the application, something is wrong.
(I have no issues with running GWT stuff from different sources).

What you did:

I take Dagger Maven example.

When I compile with mvn clean compile, it is fine.

[INFO] BUILD SUCCESS

When I try to run: mvn gwt:devmode I get BUILD FAILURE unfortunately.

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building react4j-todomvc 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> gwt-maven-plugin:1.0-rc-9:devmode (default-cli) > process-classes @ react4j-todomvc >>>
[INFO] 
[INFO] --- gwt-maven-plugin:1.0-rc-9:enforce-encoding (default-enforce-encoding) @ react4j-todomvc ---
[INFO] 
[INFO] --- gwt-maven-plugin:1.0-rc-9:add-super-sources (default-add-super-sources) @ react4j-todomvc ---
[INFO] 
[INFO] --- gwt-maven-plugin:1.0-rc-9:add-test-super-sources (default-add-test-super-sources) @ react4j-todomvc ---
[INFO] 
[INFO] --- gwt-maven-plugin:1.0-rc-9:generate-module (default-generate-module) @ react4j-todomvc ---
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ react4j-todomvc ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 7 resources
[INFO] skip non existing resourceDirectory /home/msx/workspace/java/gwt/react4j-todomvc/src/main/super
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ react4j-todomvc ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< gwt-maven-plugin:1.0-rc-9:devmode (default-cli) < process-classes @ react4j-todomvc <<<
[INFO] 
[INFO] --- gwt-maven-plugin:1.0-rc-9:devmode (default-cli) @ react4j-todomvc ---
[WARNING] Error: Could not find or load main class com.google.gwt.dev.DevMode
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.906 s
[INFO] Finished at: 2019-10-27T17:51:08+01:00
[INFO] Final Memory: 15M/392M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.ltgt.gwt.maven:gwt-maven-plugin:1.0-rc-9:devmode (default-cli) on project react4j-todomvc: GWT exited with status 1 -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Then I see that recent commits are Bazel related. So I tried with bazel. I switched to the related branch. Again no steps in documentation. So I tried to guess.

When I compile, it's fine.
I do: bazel build //:react4j_todomvc_dev and the result is OK.
Further I do bazel run //:react4j_todomvc_dev (is this the right command?). I get an error as following:

ERROR: Cannot run target //:react4j_todomvc_dev: Not executable
INFO: Elapsed time: 0.162s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (0 packages loaded)
FAILED: Build did NOT complete successfully (0 packages loaded)

Maybe I do something wrong? There are no steps what to do in README, so I tried to run it as usual.
Would you please clarify?

Did I test my environment?
Yes!
For instance, I take vue-gwt-demo .
I do mvn clean compile and I get [INFO] BUILD SUCCESS.
Further I do mvn gwt:devmode and I get

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Vue GWT demo project 1.0-beta-9
[INFO] ------------------------------------------------------------------------
...
[INFO] Super Dev Mode starting up
...
[INFO]    Loading Java files in com.axellience.vuegwtdemo.VueGwtDemo.
[INFO]    Module setup completed in 5499 ms
[INFO] 
[INFO] The code server is ready at http://127.0.1.1:9876/

I see this GWT Developement Mode window and further I go to http://127.0.1.1:8888/VueGwtDemo/ and I see the example application.
All is fine.

Suggested solution:

I tried to bump gwt-maven-plugin to the latest final and stable 1.0.0 version, but it didn't help.

Would you please suggest me where to find any simple working example for react4j?

Can we still aim for layering react4j on top of GWT-React?

I thought I would apporach you so that I can share our experience with using React from Java so far, and ideally, we all can converge our efforts in creating a one, single React library for Java. (By the way, the "react4j" name is already taken by an (inactive?) effort to introduce FRP to Java... don't know if you are aware of that, but this might cause additional confusion.)

First of all, let me share one concern: while everyone is of course free to put on GitHub their own interpretation of what React under Java should look like, the GWT/J2CL user-base is so small, that having multiple incompatible bindings of JS libraries is probably giving the wrong signals.

While I understand that your bindings are "oppinionated", as opposed to GWT-React being mostly a 1:1 mapping of the JS React API, I don't think it is impossible to layer one on top of the other so that users are able to pick one or the other approach, or even a mixture of the two (like, going with your notion of stateful components, while also using the stateless components of GWT-React).

Here's why we find stateless components useful:
Our code base is split roughly into two types of components:

  • Stateless, "dumb" components that are capable of rendering e.g. simple collections of objects and are notifying for changes via callbacks supplied in their props
  • Stateful, smart components which bind the "dumb" components from above to our models. The key thing here is that the stateful components follow the HOC pattern in a fashion similar to React-Redux, where the manual creation of smart components and the manual maintenance of their state is avoided altogether, by having a simplistic "smart" component builder, which is using a DSL to bind the models to properties of the dumb component and is thus building the smart stateful component "on the fly".

Thanks to stateless components being just functions, we don't have your issues of having to annotate lots of methods in the stateless component with @JsIgnore or @JsOverlay. Moreover, mind you, there is no complete escape path from the JSInterop annotations anyway: the Props class and the State class of each custom component have to be marked with the verbose @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") annotation.

So to summarize, we are overall happy with GWT-React, aside from some small pain points we hope to fix in future (GWTReact/gwt-react#16, GWTReact/gwt-react#9, GWTReact/gwt-react#17). If we can take measures not to divide the potential GWTReact/react4j community, that would be great.

Rename @Prop to @Input

Now that props no longer represent props on the object but potentially values sources from either the context or globally, it no longer makes sense to use @Prop. This will probably have impact on the names of other annotations and classes in the annotation processor.

Introduce @TreeLocal annotated properties

React has the concept of context values. These are essential properties that are published by a component and can be retrieved by any child component. The pre-hooks API is somewhat cumbersome and requires a render prop API in the consumer ... which is difficult if the component expects to access Arez components within the callback.

An alternative API for react4j is to add an abstract accessor method on the react4j component annotated with @TreeLocal such as:

  @TreeLocal('myService')
  abstract MyService myService();

In components annotated with @ReactComponent(type=TRACKING) we could make this an observable property and would only trigger re-renders on changes while @ReactComponent(type=STATEFUL) would re-render anytime the provider is re-rendered.

We could implement this by wrapping the native component in a regular React.Context component and adding a synthetic prop to our generated component to accept the context. (This is not too dissimilar to how hooks implement the equivalent functionality). This would allow us to have multiple context/TreeLocal values on a single component.

Port React Material Web Components

Currently react4j libraries are using a hodge-podge of custom CSS. It would be nice to have a goto library of nicely styled components. React Material Web Components is one place to look but realistically any component library would do.

This issue probably depends on us figuring out #16 first

Consider generating web components from react4j components

The way we define react4j components, it would be feasible to generate WebComponent wrappers for each react4j component that complied with certain constraints. See how Stencil.js does this as it is quite neat. Ideas could also be incorporated from lit-html and/or lit-element.

To get the code size down we may need to proceed with #49 or we could investigate the feasibility of something like rawact which compiles react components into native browser interactions in an attempt to eliminate the overhead of the reconciliation library. A similar framework is imba which you can learn about here. Actually imba + Embers AOT template compiler seem like a very very very interesting approach.

Consider using @View(public=true) parameter to control whether builder is public

View classes are not intended to be directly manipulated but we mark a class as public as a signal to the annotation processor the the generated builder should be public. We could instead force the view implementation to be package access and signal the annotation processor to generate a public builder via public=true parameter to annotation.

It seems reasonable that the default for a view could be non-public and only components that are explicitly marked as being accessible outside the package are allowed outside the package.

This is a reasonably large API change so we look at the existing projects to determine whether the juice is worth the squeeze.

Implement the Flux-Challenge

The Flux-Challenge could be reimplemented in react4j, probably drawing on the mobx example. This would be useful to highlight several weaknesses within React4j ecosystem that could be addressed. It does seem to suggest that streak would be useful but it is unclear if that is all that would be needed to make this nice.

Add Javascript Asset Loader

As the code generated by the annotation processor references native javascript classes defined in react.js, the javascript MUST be loaded prior to the GWT code defines the classes which is before the EntryPoint.onModuleLoad() is invoked. An attempt was made to load the assets via non-embedded DataResource in #25 but failed for the above reasons. The only solution seems to be to write a custom linker that either generates the host html, has a multi-stage javascript linker (that only continues loading gwt code after a chain of native js is also loaded).

However this is digging deeper into GWT2.x ecosystem when maybe the effort is better spent transitioning to J2CL. Either way, we should have a mechanism via which we use content hashing for javascript and load it as part of app startup to avoid downstream applications having to worry about caching and changes in react.js versions.

Allow @View instances to omit @Render method if they specify @View(requireRender=false)

We are seeing more and more no-render components that perform a behaviour like registering a capability while present in view tree and then removing capability when a view is not in the tree. These views always return null from the @Render annotated method. It may result in less boilerplate if we could omit the @Render if a parameter is specified to @View annotation like @View(requireRender=false)

Enable the configuration of @Input step enhancers

Currently the inputs that we supply for a component must exactly comply with the type of the input. It would be much nicer to be able to add custom methods to the step by adding some configuration to the @Input annotation

Consider the enhancer:

public interface PanelTypesEnhancer<T> {
  @Nonnull
  default T unitPanelTypes()
  {
    return panelTypes( new HashSet<>( Arrays.asList( Resource.class, Unit.class, Position.class, Role.class ) ) );
  }

  @Nonnull
  T panelTypes(@Nullable Set<Class<?>> panelTypes);
}

And the @Input

  @Input(enhancer=PanelTypesEnhancer.class)
  @Nullable
  abstract Set<Class<?>> panelTypes();

We could also convert the special case for the children input (See TODO in BuilderGenerator) to use this infrastructure.

Port a generic-ish async data load library

Several of the applications that use react4j have a backend data loading library. They may load from different data sources (i.e. GraphQL, GWT-RPC, rest, replicant, WebSockets etc.) However, it seems like they all follow similar patterns. It seems that we should be able to implement some common base functionality that the higher-level libraries could be based upon.

Typical functionality we want includes:

  • parallel requests
  • request cancellation
  • suspense support
  • Resilience to backend/network instability via backoff and retry style strategies
  • multi-level caching of results (cache results in memory, in local storage or somewhere else, maybe show stale cached value while we refetch)
  • Garbage collection of cache
  • Different refetch strategies (refetch on focus and/or every N milliseconds)
  • Invalidate specific cache entries on mutations
  • pagination of sets of values and caching of individual entries as well as pages

We could probably build something that would make this much easier by using Spritz as the coordination layer and using ideas from react-query for structure.

Spritz Integration

Could we integrate spritz with React4j such that event handlers are a stream? Props could also be passed to components as streams and then the component would subscribe and expose the values from the stream to user code (ala angular). This could be done by either generating a wrapper component or preferably by updating the existing code generator.

The Vue integration that uses a similar strategy inside a template language is described in the course. Yolk is an interesting framework that died but tackled these approaches in a react-like way.

Another integration approach is to add a "" component that takes a stream as a prop and has a render prop that has the item emitted from the stream as a parameter. See react-streams for inspiration.

Build react4j-router

The applications written on top of react4j have used a collection of different routers. Some are as simple as using arez-browserlocation while others use a state based router such as router-fu. All of them could be considered failures to some degree.

A better approach may be to build something that is a spiritual successor of react-router more aligned to java-esque patterns. It could also incorporate the planned react elements (i.e. Suspense) to reduce the responsibility of router. This may involve incorporating changes from the new kid on the block reach-router. We should also ensure capabilities like react-goodbye are easy to author. navi also has some interesting ideas.

Immutable, primitive, numeric values cause a cast error when generating the key

Adding code like:

  @Input( immutable = true )
  abstract int eventId();

Will produce code like:

  (int) inputs.get( React4j_EventCoordination.Inputs.eventId )

when generating key part for input which generates an error as the javascript number type (which is what is stored in the inputs map) is mapped to a java double/Double. Perhaps a way to fix this is to translate this to something like

  (int) (double) inputs.get( React4j_EventCoordination.Inputs.eventId )

however further testing is required

Build J2CL/Bazel Example application

J2CL is probably the target platform for React4j long term. To get there the tools probably need to mature but we can start experimenting and build out react4j-todomvc so it builds under latest bazel/j2cl/closure tool chain, potentially with js tests in place.

This is just an issue to collect some thoughts and links on how to go about this.

Links:

Create Form library

React4j does not have a form library and as a result the forms written are complex, error-prone and generate significant amounts of javascript. A better approach is to build a comprehensive form library. This would ultimately result in smaller faster, smaller, more correct code.

Before starting on this library we should review existing react projects such as formik and mobx-react-form. However the best inspiration that I am aware of comes form Angular's form library. We could probably take the design elements and features from this library and use it as the basis of a new react4j lib.

The most likely design is to include arez based model classes and pair each model component with an associated react4j component.

The view components either create and own the model elements and will dispose the model elements when they are unmounted or have elements handed to them and will just use them. If the component owns the model then it will try to register with parent which it will either determine via a prop or via Context/TreeLocal variable

Model elements would include:

  • AbstractControl - A base class for other elements.
  • FormControl - An individual input. Usually with local name.
  • FormGroup - A container for AbstractControl instances.
  • FormArray - A list of controls. Creates a new namespace but has all the same type of controls.

We could also include features from other form libraries like the "active" property from react-redux-form that indicates whether control currently is currently focused (or group has control currently focused)

Validations are also modelled the same way with view/model split so can easily render errors from react components but they are backed by model.

Autogenerate forms from DSL

Auto-generating forms from a descriptor. This is super useful and could pretty much be the way we do it for a metadata machine. The descriptor could be a json object or compiled binary format (See embers view engine for inspiration).

A comprehensive library for this is mson:

This would likely be built on the above abstractions.

Css-in-Java?

One of the current complaints with react4j is that there is no great css solution. Applications either end up using either GWT2.x css resources or static css files included via html. There is so much good css-in-js out there that we should incorporate some of it ... somehow.

Always adding `allowEmpty = true` to generated view causes problems with IDEA v2020.1 incremental compiler

The IDEA version 2020.1 has an incremental compiler that is re-running the arez annotation processor without re-running the react4j annotation processor in the same run. The react4j annotation processor specifies both @SuppressWarnings("Arez:UnnecessaryAllowEmpty") and @ArezComponent(allowEmpty = true) but the arez annotation processor is not seeing the @SuppressWarnings as it is not a source dependency and occurs in a different compilation round and thus arez generates a error and halts the compile.

We could "fix" this by not incorrectly adding allowEmpty = true (which may be a hard problem), by converting @SuppressWarnings into @SuppressArezWarnings.

Consider re-implementing the reconciliation engine in Java

The most interesting part of react that react4j uses is the reconciliation engine. It takes the vdom nodes and runs diffs between successive renders and applies the diff to the html page using a renderer. As we do not plan on using server-side rendering, a large amount of the complexity present is just not relevant in react4j.

It would be possible to reimplement the reconciliation engine in java and transpile to javascript. This would have the advantage that we could significantly improve the developer experience by adding runtime assertions, skipping the quadruple rendering that we currently do in dev mode and many other improvements. We would need to consider whether we want to support suspense-style infrastructure going forward but even doing that may be easier to do than trying to refactor our current integration layer to work with new react.

We could also easily implement "why did you render?" and easily support jre-only render tests etc.

If we get to the point where we consider re-implementing the react reconciliation layer then here is a list of helpful links that could provide useful:

If we were to ever re-implement the component model at a basic level, an interesting approach would be to allow individual components to register effects to occur at each lifecycle stage. We could also use the strategies in ivi or whatever is winning the uibench benchmark at the time. Nerv has some interesting benchmarks at https://github.com/NervJS/nerv/tree/master/benchmarks. Most interesting of all is Preact X which is small, fast, simple and has all the capabilities we seem to need. It's new DevTools integration may also be of interest as an alternative. We could also base the library on alternative strategies such as described in this article and implemented by dom-expressions.

Improved portal component

It would be nice to include a wrapper around the existing portal component to provide additional features such as those provided by react-cool-portal. In particular, it would be nice to add

  • Auto add portal container if it does not yet exist.
  • Auto remove un-used portal container for you.
  • Expose an Arez "model" object that exposes isShowing observable property and show, hide, toggle actions
  • Add props such as:
Key Type Default Description
containerId string react-cool-portal You can specify the container of portal you want by setting it as the id of the DOM element.
defaultShow boolean true The initial show/hide state of the portal.
clickOutsideToHide boolean true Hide the portal by clicking outside of it.
escToHide boolean true Hide the portal by pressing ESC key.
onShow callback   Triggered when portal is shown or the isShowing set to true.
onHide callback Triggered when portal is hidden or the isShowing set to false.

Consider renaming the generated Builder class

If you define a component MyComponent, the annotation processor will generate a builder named MyComponentBuilder. Another option is to name the builder MyComponents which is shorter and somewhat easier to use.

However, this change would be a lot of churn for limited value so only do this pre 1.0 and only if we can automate the transform and/or chunk it with other wide-ranging changes.

What is the supported React version?

Hi!
Thank you for developing this interesting project.

I see a lot of dependencies is upgraded frequently.
But there is an information which seems to be unclear to me.
What is the supported React version at the moment?

The only information I was able to find is in TODO section.
It was said about 16.4 and 16.5, but is also not clear whether any of mentioned ones is already supported.

Would you please clarify?
What is the short term goal if about the React library compatibility?
Also, if recent React versions are not relevant if about React4j approach (like no real benefits for Java-way), a word of explanation why would be also very welcome.

Thank you in advance.

Best regards,
Marcin

Add annotation to publish field/method in context

As we have started to use context more extensively the publishing side has started to get more complex. Our publishing sides often have significant nesting that may end up looking like:

  @Nonnull
  private final Context<TemplateTreeModel> _templateTreeContext = Contexts.get( TemplateTreeModel.class );
  @Nonnull
  private final Context<PoolModelService> _poolModelServiceContext = Contexts.get( PoolModelService.class );
  @Nonnull
  private final Context<OpUnitLinkModelService> _opUnitLinkModelServiceContext = Contexts.get( OpUnitLinkModelService.class );
  @Nonnull
  private final Context<TreeNodeSelectionModel> _treeNodeSelectionContext = Contexts.get( TreeNodeSelectionModel.class );

  @Render
  @Nullable
  ReactNode render()
  {
    return _templateTreeContext
      .provide( _templateTreeModel, _poolModelServiceContext
        .provide( _poolModelService, _opUnitLinkModelServiceContext
          .provide( _opUnitLinkModelService, _treeNodeSelectionContext
            .provide( _selectionModel,
                      renderUI()
            )
          )
        )
      );
  }

Which is reasonably complex. A much easier option would be to allow component authors the ability to publish components in context using an annotation on either a field or a method such as:

  @ChildOutput
  final TemplateTreeModel _templateTreeModel;

or

  @ChildOutput
  TemplateTreeModel getTemplateTreeModel() { return ....; }

React4j would be responsible for retrieving the context when the component is constructed and invoking provide during rendering. This could all be done in the derived class and could make provisions as simple as consumption

Generate warnings on unnecessary package access methods and fields in views

A few bugs have been identified as a result of other objects invoking methods on @View annotated methods. We could generate warnings if a @View declares a package access method or package-access field where it is not necessary for it to be package access. Essentially this would involve generating warnings for package-access methods and fields unless they are annotated with either an arez annotation or a react4j annotation.

This warnings should be suppress-able just in case there is a valid reason that we have yet to think of

Generate DOM host element factories from WebIDL using Akasha

Generate new host element factories from WebIDL using Akasha. Initial work has been done but progress stalled as there was no direct mapping of CSS properties and thus additional support is required.

When work continues with this we should generate host element factories for svg types at the same time.

The factory methods should use an unchecked cast of this to JsPropertyMap<Object> so we can eliminate the externs requirements in react.js when compiling using closure compiler. The ref callbacks could also be strongly typed to align with the underlying DOM element.

At the same time, we should refactor the way the dom library creates host ReactElement instances to avoid copying props and adding special handling for ref, key and children and instead creating elements directly.

We can also add some special handling around form management so we could eliminate the same from the underling react-dom.js dependency.

Use method name pattern match as a strategy for deriving immutable props

Currently, we use a number of strategies to try and derive keys from immutable props. We should add one such as detecting whether the prop type has a method named getImmutablePropKeyPart() or something similar. This avoids the misuse of existing interfaces (like Identifiable) without adding a code-level dependency upon react.

Warn when accessing mutable @Prop inside postConstruct

If we access a non-immutable prop inside postConstruct() and do not have a corresponding onPropChange for property then we should generate an invariant failure. To do this we probably need to track access behind a compile-time flag so that it is optimized out in production.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.