RelayQL: Invalid fragment composition - relayjs

I'm getting Invariant Violation: RelayQL: Invalid fragment composition, use `${Child.getFragment('name')}`. in the following. I've no idea why, and nothing seems to fix it. My component contains:
fragments: {
album: () => Relay.QL`
fragment on Album {
${AlbumMutation.getFragment('album')}
}
`,
},
AlbumMutation contains:
static fragments = {
album: () => Relay.QL`
fragment on Album {
id
}
`,
}

To anybody who runs into this, its probably due to the examples loading the React, Relay, and ReactDOM libs in the public/index.html file, instead of using the webpack import X from 'y';. If you are attempting to use the react-relay-router library, you have to use the latter, but having two copies of Relay will cause this error to occur.
I was able to fix this by removing the references in public/index.html, but its good to know that double-importing relay does seem to break this!

I was able to fix this in ES6 by removing my React/Relay imports from the component.
import React from 'react';
import Relay from 'react-relay';
class ...

Related

How can I use React Hooks with ReactJS.NET?

We are currently migrating our frontend from jQuery to Reactjs.NET. We are using React 16.8 which allows us to use React Hooks instead of classes.
We setup our project successfully and tried it first with classes and server side rendering which worked well, but my team rather use React Hooks. I tried using Webpack + Babel to transpile .jsx files since it didn't work anymore using only razor helper #Html.React(), but I still get the same error from my component.
We are using Asp.NET 4.x and NET framework 4.7.
This is my view children.cshtml
#Html.React("ChildrenForm", new {
familyTiesId = Model.FamilyTiesId
},
serverOnly:true
)
This is my ReactConfig.cs:
namespace Nop.Web
{
public static class ReactConfig
{
public static void Configure()
{
// If you want to use server-side rendering of React components,
// add all the necessary JavaScript files here. This includes
// your components as well as all of their dependencies.
// See http://reactjs.net/ for more information. Example:
ReactSiteConfiguration.Configuration
.AddScript("~/Scripts/Components/Customer/ChildrenForm.jsx");
JsEngineSwitcher.Current.DefaultEngineName = V8JsEngine.EngineName;
JsEngineSwitcher.Current.EngineFactories.AddV8();
}
}
}
My component:
import React, { useState, useEffect } from 'react';
const ChildrenForm = (props) => {
const [ familyTiesId, setFamilyTiesId ] = useState(props.familyTiesId);
...
}
It should work, but instead I get:
SyntaxError: Unexpected identifier
Line 20: #Html.React("ChildrenForm", new {
Line 21: ddtl = Model.DDTL,
Line 22: listFamilies = Model.ListFamilies,
...
[JsCompilationException: SyntaxError: Unexpected identifier
at ChildrenForm.jsx:6:8 -> import React, { useState, useEffect } from 'react';]
JavaScriptEngineSwitcher.V8.V8JsEngine.InnerExecute(String code, String documentName) +258
React.ReactEnvironment.EnsureUserScriptsLoaded() +548
It seems like we cannot import files when using razor helper #Html.React and server side rendering.
How can I do an import and use React Hooks while server side rendering?
Instead of having to import it, you can just use:
const [ familyTiesId, setFamilyTiesId ] = React.useState(props.familyTiesId);
Just call useState directly instead of importing.

Lazy loading/react-loadable in React-on-Rails

I want to lazy load all of my top-level components to improve load time. I am using react-on-rails to integrate React and Ruby on Rails. To render the components, I have to register them like so in registration.jsx:
import ReactOnRails from 'react-on-rails';
import Component1 from '../components/Component1';
import Component2 from '../components/Component2';
ReactOnRails.register({Component1, Component2});
I tried two methods:
1. React.lazy:
import {lazy} from "react";
const Component1 = lazy(() => import("../components/Component1"));
But the browser throws an error...
Uncaught Error: Module build failed: SyntaxError:
.../app/registration.jsx: Unexpected token, expected ";" (20:113)
It seems that I cannot use lazy load in this file. So I tried it in a sub component within Component1. But it still doesn't work.
const SubComponent = lazy(() => import("./SubComponent"));
This returns:
Uncaught ReferenceError: SubComponent is not defined
2. react-lodable:
Official doc
This seems to be recommended by react-on-rails (see below), but I got a different error saying react-on-rails cannot find such components.
import ReactOnRails from 'react-on-rails';
import Loadable from "react-loadable";
const loading = () => {
return <div>Loading...</div>;
}
const Component1 = Loadable({
"loader": () => import('../components/Component1'),
"loading": loading
});
import Component2 from '../components/Component2';
ReactOnRails.register({Component1, Component2});
This is the error:
Uncaught ReferenceError: ReactOnRails encountered an error while rendering component: Component1.
Original message: React is not defined
I tried to use it on a sub-component, too. But it just doesn't render it.
import Loadable from "react-loadable";
const loading = () => {
return <div>Loading...</div>;
}
const SubComponent = Loadable({
"loader": () => import("./SubComponent"),
"loading": loading
});
class Component1 extends PureComponent {
render () {
return (
<SubComponent />
)
}
}
But this only returns "loading..."
Questions:
The only good news is that Webpack is correctly splitting the bundles into smaller bundles based on components, so I think react-loadable works, but was not rendered correctly.
Is it possible to lazy load components using react-on-rails? Or am I having a syntax error? It seems that react-on-rails controls how components are loaded.
Another idea: maybe I should only do lazy loading on subcomponents. But I wonder if this will really help decreasing initial load time. Any thoughts?

AngularDart: cannot cast to a material component

I have a dart app that contains a template with a material-checkbox which I am unable to use in my component. Here is a simple template to demonstrate the problem (two_boxes.html):
<!--
Simple HTML to test checkboxes
-->
<input type="checkbox" id="cb0">
<label>Standard Checkbox</label>
<material-checkbox label="Material Checkbox" id="cb1">
</material-checkbox>
<button (click)="doTest()">Test</button>
and the corresponding component in which I try to use the checkboxes (two_boxes.dart). I can use the standard checkbox in a cast as expected but cannot find a way to do the same with the material checkbox:
// Component for testing
import 'package:angular/angular.dart';
import 'package:angular_components/angular_components.dart';
import 'dart:html';
#Component(
selector: 'two-boxes',
templateUrl: 'two_boxes.html',
directives: const [MaterialCheckboxComponent],
pipes: const [
COMMON_PIPES
])
class TwoBoxes {
// Get the the two checkboxes and see if they are checked
void doTest() {
var checkbox_standard = querySelector("#cb0");
print(checkbox_standard.runtimeType.toString()); // InputElement
print((checkbox_standard as CheckboxInputElement).checked); // Succeeds
var checkbox_material = querySelector("#cb1");
print(checkbox_material.runtimeType.toString()); // HtmlElement
print((checkbox_material as MaterialCheckboxComponent).checked); // Error!
}
}
The last statement fails when I run the app in Dartium following a "pub serve" (no errors) with:
VM54:1 EXCEPTION: type 'HtmlElementImpl' is not a subtype of type
MaterialCheckboxComponent' in type cast where HtmlElementImpl is
from dart:html MaterialCheckboxComponent is from
package:angular_components/src/components/
material_checkbox/material_checkbox.dart
Clearly this way of casting does not work. I searched for hours how to solve this error and find the correct way to do this but obviously in the wrong places. What am I missing here? I am using Dart VM version 1.24.2.
There is no way to get the component instance from an element queried this way.
You can use #ViewChild()
class TwoBoxes implements AfterViewInit {
#ViewChild(MaterialCheckboxComponent) MaterialCheckboxComponent cb;
ngAfterViewInit() {
print(cb.checked);
}
to get a specific one if you have more than one, you can use a template variable
<material-checkbox #foo label="Material Checkbox">
with
#ViewChild('foo') MaterialCheckboxComponent cb;
You can find more information about this topic in this TypeScript answer angular 2 / typescript : get hold of an element in the template
The syntax is a bit different (type annotations on the right and {} around the optional read parameter, which are not used in Dart.

Polymer-Dart Equivalent Functions

I'm trying to work through a Google I/O codelab for the Material Design Web App, but port it to the Dart language. http://io2014codelabs.appspot.com/static/codelabs/polymer-build-mobile/#4
I'm at the step where you toggle the drawer, but I can't figure out the dart equivalent.
The JS code to toggle the drawer looks like this:
<script>
Polymer('codelab-app', {
toggleDrawer: function() {
this.$.drawerPanel.togglePanel();
}
});
</script>
I have tried the following in my CodelabApp class, but I get a NoSuchMethodError: method not found: 'togglePanel'
#CustomTag('codelab-app')
class CodelabApp extends PolymerElement {
CodelabApp.created() : super.created() {}
void toggleDrawer() {
querySelector('core-drawer-panel')..togglePanel();
}
}
my button element properly fires, but I can't figure out how to call the drawer's togglePanel method. <paper-icon-button icon="menu" on-click="{{toggleDrawer}}"></paper-icon-button>
any help or direction to the proper docs would be greatly appreciated.
UPDATE:
This has been fixed in recent versions: https://github.com/dart-lang/core-elements/issues/39
Updating the polymer and core_elements libraries works as expected.
While attempting to commit my own fix to this, I discovered a temporary workaround that works in my case. Maybe will work for you :)
Add the following to the top of your file:
import 'dart:js' show JsObject;
_js(x) => new JsObject.fromBrowserObject(x);
Then change your custom tag code:
#CustomTag('codelab-app')
class CodelabApp extends PolymerElement {
CodelabApp.created() : super.created() {}
void toggleDrawer() {
_js(shadowRoot.querySelector('core-drawer-panel')).callMethod('togglePanel');
}
}
For reference I found this solution by reading through the code here:
https://github.com/dart-lang/core-elements/blob/master/example/core_drawer_panel.html#L68-L81

Duplicate top-level declaration 'METHOD main' in dart

I'm new to dart, and trying to use dart to write a hello world and a unit test, but I get the error:
duplicate top-level declaration 'METHOD main' at ../app.dart::5:6
My project dir is test-dart, and it has 3 files.
test-dart/models.dart
class User {
hello(String name) {
print("Hello, ${name}");
}
}
test-dart/app.dart
#library("app");
#source("./models.dart");
void main() {
new User().hello("app");
}
test-dart/test/test.dart
#library("test");
#import("../app.dart");
void main() {
print("hello, test");
}
Now there is an error in "test.dart" on void main(), the error message is:
duplicate top-level declaration 'METHOD main' at ../app.dart::5:6
The two main() methods are in different libraries, why they are still duplicated? How to fix it?
If you import a library like this #import('../app.dart), then all names from app.dart become visible in the importing code (all public names, actually -- those that don't start with a _). So in your test.dart library, you now have two main functions visible. That is obviously a collision. There are two ways to solve it (that I know of).
First: import the library with a prefix, like this: #import('../app.dart', prefix: 'app'). Then, all public names from app.dart are still visible, but only with an app prefix, so the main function from app.dart is only accessible by app.main. No collision here, but you have to use a prefix everytime.
Second: using a show combinator, like this: #import('../app.dart', show: ['a', 'b']). Then, it is no longer true that all names from app.dart are visible, only those explicitly named (a and b here). I'm not sure if this is already implemented, though.
Maybe in the future, we will get something opposite to the show combinator, so that you could do #import('../app.dart', hide: ['main']). That would be the best solution for your problem, but it isn't in the current language (as specified by 0.09).
You are importing app.dart without a prefix which means that the symbols of the importing and imported library can collide if there are duplicates such as in your example.
To resolve these collisions the library import allows you to prefix imports with an identifier. Your example should work if you change test.dart as follows:
#library("test");
#import("../app.dart", prefix: "app");
void main() {
print("hello, test");
app.main();
new app.User().hello("main");
}
Notice how the classes and top-level functions in the app.dart library are now accessed using the "app" prefix and thus do not collide with the names in test.dart.

Resources