Adding HTML to a React Three Drei 'Instance' - three.js

I've been looking at this example here:
https://codesandbox.io/s/floating-instanced-shoes-h8o2d?file=/src/App.js
Which uses <Instances><Instance> from React Three Drei..
The docs: https://github.com/pmndrs/drei#performance say that html can be passed over inside an instance like so:
<Instance>
<Html>hello from the dom</Html>
</Instance>
However, in the shoes example, if I pass like this (Html needs to be imported from Drei library):
import { Html, Instances, Instance, OrbitControls, Environment, useGLTF } from '#react-three/drei'
...
return (
<group {...props}>
<Instance ref={ref} onPointerOver={(e) => (e.stopPropagation(), setHover(true))} onPointerOut={(e) => setHover(false)}>
<Html>Hello from the DOm</Html>
</Instance>
</group>
)
The html keeps getting added recursively (watch out if you try it).
Is there any way to make sure it gets added 1 time for each item, or will I need to refactor the whole example to use <mesh> or something instead of <Instance>?

Related

The application on react + redux + react-dnd does not work after assembly, why?

when running the test script an error occurs
Invariant Violation: Could not find "store" in the context of "Connect (DragD
ropContext (App)) ". Either wrap the root component in a,
or pass a custom React context provider to and the
corresponding React context Consumer Connect (DragDropContext (App)) in connect options.
although everything works in an unassembled project. As I understand it, there are some problems due to the fact that the root component is wrapped in two hocs - one redox, the other dnd.
ReactDOM.render(<DragDropContextProvider backend={HTML5Backend}>
<Provider store={store}>
<App />
</Provider>
</DragDropContextProvider>, document.getElementById('root'));
I tried to wrap first in dnd, then in redaks - it did not help, everything is the same.
It seems you mixed up the legacy decorator API with the top-level API
Legacy Decorator API
With legacy decorator you can wrap as following:
import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
class YourApp {
/* ... */
}
export default DragDropContext(HTML5Backend)(App)
Check the documentation about Legacy Decorator API here...
Top-Level API
For the Top-Level API you use:
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
....
...
<div className="App">
<DndProvider backend={HTML5Backend}>
<App />
</DndProvider>
</div>
Check the documentation about Top-level API here...

SharepointFramework - how to set the actual webpart code as initial value in PropertyFieldCodeEditor

Hello i am using this custom property pane control called PropertyFieldCodeEditor. what i want is to display the actual webpart code as the initial value of the code editor, then after i click save, the changes will be reflected on the webpart..
this is the code of PropertyFieldCodeEditor
PropertyFieldCodeEditor('htmlCode', {
label: 'Edit Code',
panelTitle: 'Edit Code',
initialValue: "",
onPropertyChange: this.onPropertyPaneFieldChanged,
properties: this.properties,
disabled: false,
key: 'codeEditorFieldId',
language: PropertyFieldCodeEditorLanguages.HTML
})
i tried to put this.domElement on initialvalue but it only accept string, also i cand find a way to convert this.domelement to string..
also what should i put inside
protected onPropertyPaneFieldChanged(path: string, newValue: string) {}
For initialValue, you should be able to use this.domElement.innerHTML or this.domElement.outerHTML. Both are strings representing the contents of domElement (note, domElement is really just an HTMLElement).
outerHTML will include everything, including one extra div layer on the outside:
<div style="width: 100%;">
<div class="helloWorld_d3285de8">
...
</div>
</div>
innerHTML is only the inside contents of that div:
<div class="helloWorld_d3285de8">
...
</div>
You'll probably want innerHTML, since that's what's initially used in the render method.
Once you set the initialValue, you would have accomplished copying your web part code into the PropertyFieldCodeEditor. Now you would need to get the PropertyFieldCodeEditor contents (which is stored in your property htmlCode) assigned back into this.domElement.innerHTML.
Unfortunately, in onPropertyPaneFieldChanged, this points to the PropertyFieldCodeEditor, not to the web part class anymore. You may or may not be able to do it here - I didn't look too deeply into it.
The easiest solution I figured was, in render, to assign this.domElement.innerHTML like so:
public render(): void {
this.domElement.innerHTML = this.properties.htmlCode || `
<div class="${styles.helloWorld}">
...
</div>`;
}
This way, the web part will initially render whatever comes after the ||. But as soon as you save a change to the PropertyFieldCodeEditor, it will start rendering the htmlCode instead. This only works because initially htmlCode is undefined. (Note it won't work exactly like this if you assign something truthy to it via your web part's preconfiguredEntries - you would have to write some further checks. The principle is the same, though.)

Field component not providing 'input.onChange' property

on the Redux form docs (http://redux-form.com/6.5.0/docs/api/Field.md/) for Field, it says there is supposed to be an onChange property (props.input.onChange), but my components dont' get provided with any such property.
const customComponent = props => {
console.log(`input: ${JSON.stringify(props.input)}`);
return (
<Jsx ... />
);
};
//Using it:
<Field name="link_id" component={customComponent} />
This prints input: {"name":"link_id","value":""}
Is there something I'm doing wrong here?
Your component has those properties, they are not printed because JSON.stringify can't just stringify and output any functions (such as onChange).
What you see running your code are only the properties of your Field (name and value) which are strings and thus can be stringified and printed.
If you want to explore your Field object just use debugger in your component or use breakpoints or simply
console.log(props.input.onChange);

call to ReactJS component in Laravel blade templates

I use Laravel 5.4 and React 15.5.4, code is writing in ES6.
I'd like replace Vue and use React and I did it. But I often will use small components for example 2 in different places of blade template. I don't want use one app component.
I'd like use something like:
<span class="react">
<TestComponent property={true} />
</span>
I can't do it automatically. Now I use
<span data-component="TestComponent" data-props="{property:true}" />
and in app.js
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
if(item.name !== 'data-react'){
element.removeAttribute(item.name);
}
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works but I need to use add all properties to one react component property and then use for example this.props.out.propery
I also would like set normal component tag in my blade component
I've try to use in app.js
_.each(document.querySelectorAll('.react'), item => {
ReactDOM.render(item.children,item);
});
Someone have any idea to solve this problem?
EDIT
I changed my solution to:
<span data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
or
<LoginForm data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
in blade and in resources/assets/js/app.js
var reactComponents = {
LoginForm: require('./components/login').default,
};
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works fine. This is not super clear solution but I have impression that the reasonable.
I can set components name in html code and add props almost same like in JSX.
As far as I know, you can not mix JSX components directly with Blade templates. The only server side rendering available today for React is NodeJS.
What you could do to improve your architecture is add specific HTML tags with certain ids and render the react components in them. So inside Blade you could do something like:
<div id="componentA"></div>
This will act as a place holder in your Blade template for that react component. Then you render your componentA from your app.js like this:
React.render(<ComponentA prop1='valueX'/>, document.getElementById("componentA"))
Remember that in this case the world of react and world of Blade run at different times.
You could use document.getElementsByTagName('LoginForm') getting all the instances and later iterate its attributes. It's clear code but not generic, because it will work just for LoginForm components.
If you want to render any tag name, then maybe it's better to use some attribute as you used with data-react.
getElementsByTagName isn't super supported by old browsers so maybe could a good idea to use jQuery as fallback $('LoginForm')

Angular2 component without view annotation

I would like to be able to use Angular2 to do client-side databinding on my server-rendered pages (ASP.Net MVC6).
Is it possible to do this without adding a #view template? Instead of defining it inline or creating an external template, I would like to enclose a block of server-rendered HTML with the app element. This was how I did it in Angular1, as it allows me to choose whether to databind on the server-side or on the client-side.
Thanks.
You can do something similar, that is probably what you want. Take this example:
import {Component, View, bootstrap} from "angular2/angular2";
#Component({
selector: "app"
})
#View({
template: "<content></content>"
})
export class App {
public name: string;
constructor() {
this.name = "MyName";
}
}
bootstrap(App);
The template has a special content
<content></content> that represents the ngTransclude directive. This will allow you to add content inside the app tag:
<app>
<h1>Hello World</h1>
</app>
Unfortunately this is still poorly undocumented and changing so it's hard to tell about the actual limitations or even if this will remain like this.
Regards.

Resources