canjs
canjs copied to clipboard
ReactDefineElement
Creating this to discuss what the purpose of ReactDefineElement is and try to determine what people will want / expect from it.
What is the goal of ReactDefineElement
To create a JSX view layer, one people will be useful is to allow users to use different templating languages to create custom-elements. JSX provides a familiar interface to people familiar with React.
Who is likely to use it
Project's that use both CanJS & React, having a common templating language will be easier to switch between projects and even allow the easier ability to use common components.
The big questions to me are:
- Can you use an element created by
ReactDefineElement
from a React Component? There are issues using custom elements in React applications. - Can you use existing React Components inside an element created by
ReactDefineElement
?
The answers to these questions will determine who might want to use a project like this and how hard it will be to implement.
@phillipskevin (1) is trivial to work around so there's no problem there.
(1) is trivial to work around so there's no problem there.
@matthewp can you explain what you mean? If we want to make it possible to pass an object to a ReactDefineElement
property from a React component, is there an easier way than using a Ref?
@phillipskevin Yeah a ref is what I mean. You can solve this in a few different ways that doesn't expose the problem to the users (providing a way to create a React component wrapper for example). Maybe saying it is trivial is too strong, there are tradeoffs to whichever solution is chosen.
Below is an example of what it might look like to "just" support using JSX in a CanJS Custom Element. To make this, I set up this example with the existing StacheDefineElement and then just updated the stache view to be JSX instead and updated the name of the imported base class.
import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import { ReactDefineElement } from "can/ecosystem";
class PersonForm extends ReactDefineElement {
static get define() {
return {
first: String,
last: String,
firstChangeHandler: Function,
lastChangeHandler: Function
};
}
static get view() {
return (
<p>First: <input value={this.first} onChange={this.firstChangeHandler}></input></p>
<p>Last: <input value={this.last} onChange={this.lastChangeHandler}></input></p>
<p>{this.fullName}</p>
);
}
get fullName() {
return `${this.first} ${this.last}`;
}
}
customElements.define("person-form", PersonForm);
function App() {
const [person, setPerson] = useState({ first: "Kevin", last: "McCallister" });
const nameForm = useRef();
const setFirst = ev => {
setPerson({ ...person, first: ev.target.value });
};
const setLast = ev => {
setPerson({ ...person, last: ev.target.value });
};
useEffect(() => {
const el = nameForm.current;
el.first = person.first;
el.last = person.last;
el.firstChangeHandler = setFirst;
el.lastChangeHandler = setLast;
});
return (
<div className="App">
<person-form ref={nameForm}></person-form>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);