SabakiHQ / Shudan

A highly customizable, low-level Preact Goban component.
MIT License
82 stars 22 forks source link

Use in a React project? #1

Closed hadim closed 5 years ago

hadim commented 5 years ago

How hard would it be to use this lib in a React project? I found a lot of examples to use React components into Preact projects but the other way...

yishn commented 5 years ago

I haven't tested it at all, but in theory, I've kept everything as compatible as possible to React. It should be as easy as aliasing the preact module to react in your favorite bundler. Maybe you can try it out?

hadim commented 5 years ago

Ok. I'll try that. Thanks.

mberd commented 5 years ago

@hadim this is how you can do it, it's a React wrapper for preact component

credit goes to this author https://swizec.com/blog/seamlessly-render-preact-component-react-project/swizec/8224

/** @jsx h */
import React from 'react';
import Preact, {h} from 'preact'

import { Goban } from '@sabaki/shudan'

export default class GobanWrapper extends React.Component {
    constructor(props) {
        super(props);

        let boardSize = props.boardSize ? props.boardSize : 19
        let vertexSize = props.vertexSize ? props.vertexSize : 19
        this.state = { 
            boardSize: boardSize,
            vertexSize: vertexSize, 
            signMap: props.signMap ? props.signMap : this.generateBoardSignMap(19) 
        };
    }

    componentDidMount() {
        this.renderPreact()
    }

    componentDidUpdate() {
        this.renderPreact
    }

    renderPreact() {
        Preact.render(
            <Goban vertexSize={this.state.vertexSize} signMap={this.state.signMap} />, 
            this.refs.goban
        )
    }

    generateBoardSignMap(size) {
        const x = new Array(size);
        for (let i = 0; i < size; i++) {
            x[i] = new Array(size);
            for (var j = 0; j < size; j++) {
                x[i][j] = 0;
            }
        }

        return x;
    };

    resetBoard() {
        this.setState({boardSize: this.state.newSize })
    };  

    render() {
        let h = React.createElement
        return <div ref="goban"></div>
    }
}
yishn commented 5 years ago

@mberd I don't think it's necessary to create a wrapper like that. In doing so, you'll need to bundle Preact as well as React in your webapp which is a little too much. Does it not work if you alias preact as react in webpack? If not, we should investigate and get it fixed.

mberd commented 5 years ago

@yishn first - big thanks for writing this :)

this is the error i am getting

Warning: The component appears to have a render method, but doesn't extend React.Component. This is likely to cause errors. Change Goban to extend React.Component instead.

and I don't know/couldn't find how to use alias in webpack... :(

mberd commented 5 years ago

fixed in webpack.config.js:

resolve: {
    alias: {
      preact: "react"
    },
    extensions: ['*', '.js', '.jsx']
  },

now only this warning:

Warning: Unsafe legacy lifecycles will not be called for components using new component APIs.

Goban uses getDerivedStateFromProps() but also contains the following legacy lifecycles: componentWillReceiveProps

The above lifecycles should be removed. Learn more about this warning here: https://fb.me/react-async-component-lifecycle-hooks

yishn commented 5 years ago

Exactly, you have to alias preact as react. You can safely ignore the warning, since componentWillReceiveProps() is there for compatibility reasons with Preact. I guess everything works with React then? I'll close this issue, then.

psygo commented 10 months ago

I'm trying to make this work on NextJS but haven't been able to so far. Does anyone have a tip?

The core of the issue I'm having I believe is this:

Error: Class constructor Goban cannot be invoked without 'new'

This is apparently because Preact didn't use new to instantiate components but newer versions of React require it? Some solutions recommend using target: "es6" in your tsconfig.json to circumvent it, but I'm already doing that...

I'm having to use a // @ts-ignore because otherwise this is what I get:

'Goban' cannot be used as a JSX component.
  Its type 'ComponentClass<GobanProps, {}>' is not a valid JSX element type.
    Type 'ComponentClass<GobanProps, {}>' is not assignable to type 'new (props: any, deprecatedLegacyContext?: any) => Component<any, any, any>'.
      Property 'refs' is missing in type 'Component<GobanProps, {}>' but required in type 'Component<any, any, any>'.ts(2786)
index.d.ts(543, 9): 'refs' is declared here.

Here's what I have on my page.tsx:

// import { h } from "preact";
import { Goban } from "@sabaki/shudan";

export function CustomComponent() {
  return (
    // @ts-ignore
    <Goban
      vertexSize={24}
      signMap={[
        [0, 0],
        [0, 0],
      ]}
    />
  );
}

export default function Home() {
  return (
    <>
      <CustomComponent />
    </>
  );
}

My next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: {
    resolve: {
      alias: {
        preact: "react",
        "preact/hooks": "react", // I have tried it with or without this line
      },
      extensions: ["*", ".js", ".jsx", ".ts", ".tsx"],
    },
  },
};

module.exports = nextConfig;

I'm using NextJS 14, here are the key dependencies on my package.json:

{
    "@sabaki/shudan": "^1.7.1",
    "next": "14.0.2",
    "preact": "^10.19.2",
}
psygo commented 8 months ago

Here's an first attempt (I've actually tried many variations of it already): @psygo/embed_shudan

If anyone manages to get a template going, I would greatly appreciate it.

andrew-taylor-2 commented 1 month ago

I got it working with vite in my vite.config.js with

export default defineConfig({ plugins: [react()], resolve: { alias: { 'preact/hooks': 'react', preact: 'react', }, extensions: ['*', '.js', '.jsx', '.ts', '.tsx'] } });

I think the order of those aliases matters. Let the record reflect I'm not very knowledgeable about JS at all.

psygo commented 1 month ago

@andrew-taylor-2 could you maybe share a template repo?