canjs icon indicating copy to clipboard operation
canjs copied to clipboard

ReactDefineElement

Open Mattchewone opened this issue 5 years ago • 5 comments

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.

Mattchewone avatar Jun 03 '19 14:06 Mattchewone

The big questions to me are:

  1. Can you use an element created by ReactDefineElement from a React Component? There are issues using custom elements in React applications.
  2. 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 avatar Jun 03 '19 14:06 phillipskevin

@phillipskevin (1) is trivial to work around so there's no problem there.

matthewp avatar Jun 03 '19 15:06 matthewp

(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 avatar Jun 03 '19 15:06 phillipskevin

@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.

matthewp avatar Jun 03 '19 16:06 matthewp

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);

phillipskevin avatar Jun 04 '19 19:06 phillipskevin