Coder Social home page Coder Social logo

Comments (9)

neongreen avatar neongreen commented on April 27, 2024 1

I also don't see a use case where you would want to return such functions from the sketch itself, perhaps you can elaborate on this?

I'll try to elaborate.

  • I have a game written as a p5 sketch. The game has some kind of internal state.
  • I want to continue to use p5 to display the game canvas itself (because p5 is good at drawing).
  • However, I also want to use React for the rest of the interface (because React is good at UIs).

This means that if I want to bind some in-game actions to React elements (buttons, etc), I have two options as far as I see:

  1. I can continue storing my in-game state in p5. I will also construct and return some kind of a "handle" in my p5 code. This handle will contain a bunch of methods (in-game actions) that React can call. Think of an HTML5 <video> element having methods like play() and pause().

  2. Alternatively, I can move all my state to React. Then the sketch will just purely/declaratively display this state. All state modifications will happen in React.

I don't see these options as "composition vs inheritance", but rather "who manages the state" — React or p5. I want the state to be managed by p5. I understand that React prefers controlled components and moving all state into React, but I don't want to move all my game state into React just because I want to have a button that asks my game to do something.

I also don't mind the runtime overhead (I think?).

from react.

neongreen avatar neongreen commented on April 27, 2024 1

Yeah, that's fair. If there's no easy way then sure

from react.

jamesrweb avatar jamesrweb commented on April 27, 2024

I don't understand what you mean exactly by "expose methods". Could you provide an example implementation of what you have in mind?

from react.

neongreen avatar neongreen commented on April 27, 2024

Sure.

Sketch:

// sketch.ts

type Methods = {
  resetGame: () => void,
  getPosition: () => number,
}

export function sketch(p5): Methods = {
  ...p5 code...
  return {
    resetGame: () => ...
    getPosition: () => ...
  }

React:

// index.tsx

const game = (p5) => {
  const methods = sketch(p5)
  window.methods = methods
}

function Page() {
  return (
    <>
      <button onClick={window.methods.reset}>Reset</button>
      ...
      <NextReactP5Wrapper sketch={game} />
    </>
  )
}

Now I can call window.methods.[whatever] to manipulate the sketch.

For sure, I can also achieve sketch control by using props and p5.updateWithProps. But specifically for things like reset(), I think it's nicer to have an imperative handle instead of [resetFlag, setResetFlag] = useState(false) or whatever would be the React way of doing it.

See also: useImperativeHandle() is very close to what I want.

from react.

jamesrweb avatar jamesrweb commented on April 27, 2024

Sure.

Sketch:

// sketch.ts



type Methods = {

  resetGame: () => void,

  getPosition: () => number,

}



export function sketch(p5): Methods = {

  ...p5 code...

  return {

    resetGame: () => ...

    getPosition: () => ...

  }

React:

// index.tsx



const game = (p5) => {

  const methods = sketch(p5)

  window.methods = methods

}



function Page() {

  return (

    <>

      <button onClick={window.methods.reset}>Reset</button>

      ...

      <NextReactP5Wrapper sketch={game} />

    </>

  )

}

Now I can call window.methods.[whatever] to manipulate the sketch.

For sure, I can also achieve sketch control by using props and p5.updateWithProps. But specifically for things like reset(), I think it's nicer to have an imperative handle instead of [resetFlag, setResetFlag] = useState(false) or whatever would be the React way of doing it.

See also: useImperativeHandle() is very close to what I want.

I'm not sure this brings any benefits that composition couldn't already give you. For example when we want to have a draw function, we create it in the global scope and pass the p5 instance through to it as shown in the documentation.

I also don't see a use case where you would want to return such functions from the sketch itself, perhaps you can elaborate on this?

The useImperativeHandle hook brings a lot of overhead at runtime and is warned against in the docs themselves:

Do not overuse refs. You should only use refs for imperative behaviors that you can’t express as props: for example, scrolling to a node, focusing a node, triggering an animation, selecting text, and so on.

If you can express something as a prop, you should not use a ref. For example, instead of exposing an imperative handle like { open, close } from a Modal component, it is better to take isOpen as a prop like . Effects can help you expose imperative behaviors via props.

I think generally what I see from your example code is that we could have a reset function for example in the global scope which receives the p5 instance and the current game state and can then return the new game state accordingly.

This would be much cleaner and more predictable in terms of behaviour and readability.

Perhaps I missed your point and if so, I would love to hear more so I can help further but it seems to me that composition over inheritance would be the principle to go with here as things stand. What do you think? 😊

from react.

jamesrweb avatar jamesrweb commented on April 27, 2024

Can you provide a minimal code example of how you'd propose this would work? I know you provided one above but due to how p5 itself works, I don't see this is possible with instance mode without rewiring the internals or factory functioning the implementation. Even then, I am still concerned about the runtime cost and the developer experience of implementing things this way.

It would be to open a PR, if you're willing to create one, to discuss this more concretely on an implementation level as to what you're hoping for.

from react.

neongreen avatar neongreen commented on April 27, 2024

I don't know how to make this work.. but I also wouldn't expect myself to know, given that I'm not an advanced user of either p5 or React.

due to how p5 itself works, I don't see this is possible with instance mode without rewiring the internals or factory functioning the implementation.

Hmmm. Can you elaborate?

from react.

jamesrweb avatar jamesrweb commented on April 27, 2024

P5 has two modes: instance mode and global mode.

Global mode is where you have all the P5 functions, etc in the global scope like most p5 projects have.

Instance mode is where you create a new instance of the P5 class and then use the functions (methods) on that class instance. In the case of libraries such as this one, instance mode is the only and best option!

In instance mode you need to provide a sketch function which will recieve the p5 instance and this is exactly what you are passing into the component exposed from this library. In turn you then use the methods on that provided p5 object such as p5.setup, etc.

That function cannot return arbitrary functions to you as the user as it is not intended for that purpose on a p5 level. You can however create a factory to generate your desired functions and to return your sketch if you really must, something like:

function someFactory() {
  let var1 = 0;
  let var2 = "test";

  return {
    func1() {...},
    func3() {...},
    game(p5) { 
      p5.updateWithProps = props => {
         var1 = props.whatever;
      } 
    }
  }
}

const { func1, func3, game } = someFactory();

...
 <NextReactP5Wrapper sketch={game} />
...

Something like that is what I assume you are looking for and it's the closest you can get to what you seem to be describing. Library wise there is really nothing we could change based on my current understanding of your wishes, it would need to be done on your end with something like the above.

from react.

jamesrweb avatar jamesrweb commented on April 27, 2024

Closing due to inactivity. Please reply to re-open if necessary.

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.