How to pass React prop into setup()?

Hi legends, I’m trying to figure out a problem with combining React UI with p5.js
Currently I’m using p5-react-wrapper.
I do aware @atoro has a more advanced and elegant solution (but it’s currently too complicated) for me to understand and use ):

I’m currently trying to create a slider in React (HTML input range) that will control the diameter of my particles. The prop value is able to get passed into init function scope but not into the setup(). I believe setup() is only run once. If I use the OOTB createSlider from p5 it’ll work but I can’t hook it up with my own React UI.

In my Sketch.tsx

import Particle from "./Particle"
import "p5/lib/addons/p5.dom.min"

export default function sketch(p) {
    let bug1, bug2, diameter
    diameter = 10 // Default value
    
    const init = () => {
        console.log("here0 " + diameter) // Diameter value will get updated when you drag the slider (but not sure how I can pass it into setup()?
        p.setup = () => {
            p.createCanvas(710, 400)
            // diameter = p.createSlider(10, 30, 15, 1)
            bug1 = new Particle(p, diameter)
            bug2 = new Particle(p, diameter)
        }
    }
    init()

    p.myCustomRedrawAccordingToNewPropsHandler = function(props) {
        if (props.diameter) {
            diameter = props.diameter
        }
    }

    p.draw = () => {
        init() // The prop value is able to get read here in the draw() function
        p.background(50, 89, 100)
        bug1.move()
        bug1.display()
        bug2.move()
        bug2.display()
    }
}

Particle.js

export default class Particle {
    constructor(p5, diameter) {
        this.p5 = p5
        this.diameter = diameter
        this.x = this.p5.random(300)
        this.y = this.p5.random(300)
        this.speed = 1
    }

    move() {
        this.x += this.p5.random(-this.speed, this.speed)
        this.y += this.p5.random(-this.speed, this.speed)
    }

    display() {
        this.p5.ellipse(
            this.x,
            this.y,
            // this.diameter.value(),
            // this.diameter.value()
            this.diameter,
            this.diameter
        )
    }
}
1 Like

@venn
demo

import React, { useState } from 'react'
import P5Wrapper from 'react-p5-wrapper'
import { render } from 'react-dom'

const NUMBER_OF_BUGS = 5

class Particle {
    constructor(p, diameter) {
        this.p = p
        this.diameter = diameter
        this.scale = this.p.random(0.5, 2.5)
        this.x = this.p.random(300)
        this.y = this.p.random(300)
        this.speed = 1
    }

    move() {
        this.x += this.p.random(-this.speed, this.speed)
        this.y += this.p.random(-this.speed, this.speed)
    }

    display() {
        this.p.circle(this.x, this.y, this.diameter * this.scale)
    }
}

function sketch(p) {
    const bugs = []
    let diameter = 0

    p.setup = () => {
        p.createCanvas(600, 400)
        for (let i = 0; i < NUMBER_OF_BUGS; i++) {
            bugs.push(new Particle(p, diameter))
        }
    }

    p.myCustomRedrawAccordingToNewPropsHandler = (props) => {
        if (props.diameter) {
            diameter = props.diameter
        }
    }

    p.draw = () => {
        p.background(127)
        bugs.forEach((bug) => {
            bug.move()
            bug.diameter = diameter
            bug.display()
        })
    }
}

function App() {
    const [diameter, setDiameter] = useState(15)
    return (
        <>
            <label htmlFor="slider">
                <input
                    id="slider"
                    type="range"
                    min={10}
                    max={30}
                    step={1}
                    value={diameter}
                    onChange={event => setDiameter(+event.target.value)}
                />
                {diameter}
            </label>
            <P5Wrapper sketch={sketch} diameter={diameter} />
        </>
    )
}

render(<App />, window.document.querySelector('#app-root'))

1 Like

OMG thanks! @atoro
You fix my problem that I struggle to fix the whole night!

Btw, quick question,
+e.target.value I know this is converting string --> number but how does this work? Putting a “+” infront?

The unary plus operator + is the cheapest way to coerce most datatypes to number: :heavy_plus_sign:

2 Likes

Btw, quick question,
+e.target.value I know this is converting string → number but how does this work? Putting a “+” infront?

1 Like