skip to Main Content

I was trying to use react-py to use pyodide in my NextJs app. It requires it wrap the component where python is to be used with `PythonProvider`. I have used the PythonProvider and usePython in the same page (client side) but the sendInput stopped working.

After some debugging I figured out that the input related values in the PythonProvider was changing but it was not updated in usePython hook (wrapper of PythonContext). But surprisingly if I move the Provider to layout.js it starts working fine.

Is there any restriction in place that ContextProvider and useContext mustn’t be used in the same page?

Not Updating Page.js

'use client'
import { useState,useEffect } from 'react'
import { PythonProvider, usePython } from '../../react-py/src'


const Page = () => {
  const [code, setCode] = useState('input("hello:")')
  const {interruptExecution,isAwaitingInput,isLoading,isReady,isRunning,prompt,runPython,sendInput,stderr,stdout}=usePython()

  useEffect(() => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then((registration) =>
        console.log(
          'Service Worker registration successful with scope: ',
          registration.scope
        )
      )
      .catch((err) => console.log('Service Worker registration failed: ', err))
  }, [])


  return (
    <PythonProvider>
      {isAwaitingInput && <p>INPUT A</p>}
      {isLoading && <p>Loading A</p>}
      {isReady && <p>READY A</p>}
      {isRunning && <p>RUNNING A</p>}
      <input type="text" value={code} onChange={e=>setCode(e.target.value)}/>
      <button onClick={e=>{runPython(code)}}>RUN</button>
      <button onClick={e=>{sendInput('sdfghj')}}>SEND INPUT</button>
      <button onClick={e=>{interruptExecution()}}>INTERUPT</button>
      <p>{stdout}</p>
    </PythonProvider>
  )
}

export default Page

Though this works->
layout.js

'use client'
import { Inter } from "next/font/google";
import "./globals.css";
import { useEffect } from "react";
import { PythonProvider } from "../../react-py/src";

const inter = Inter({ subsets: ["latin"] });


export default function RootLayout({ children }) {
  useEffect(() => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then((registration) =>
        console.log(
          'Service Worker registration successful with scope: ',
          registration.scope
        )
      )
      .catch((err) => console.log('Service Worker registration failed: ', err))
  }, [])


  return (
    <html lang="en">

      <PythonProvider>

        <body className={inter.className}>{children}</body>
      </PythonProvider>
    </html>
  );
}

`page.js`

'use client'
import { useState,useEffect } from 'react'
import { PythonProvider, usePython } from '../../react-py/src'


const Page = () => {
  const [code, setCode] = useState('input("hello:")')
  const {interruptExecution,isAwaitingInput,isLoading,isReady,isRunning,prompt,runPython,sendInput,stderr,stdout}=usePython()

  return (
    <>
    
      {isAwaitingInput && <p>INPUT A</p>}
      {isLoading && <p>Loading A</p>}
      {isReady && <p>READY A</p>}
      {isRunning && <p>RUNNING A</p>}
      <input type="text" value={code} onChange={e=>setCode(e.target.value)}/>
      <button onClick={e=>{runPython(code)}}>RUN</button>
      <button onClick={e=>{sendInput('sdfghj')}}>SEND INPUT</button>
      <button onClick={e=>{interruptExecution()}}>INTERUPT</button>
      <p>{stdout}</p>
    </>
  )
}

export default Page
...

2

Answers


  1. 'use client'
    import { Inter } from "next/font/google";
    import "./globals.css";
    import { useEffect } from "react";
    import { PythonProvider } from "../../react-py/src";
    
    const inter = Inter({ subsets: ["latin"] });
    
    export default function RootLayout({ children }) {
      useEffect(() => {
        navigator.serviceWorker
          .register('/service-worker.js')
          .then((registration) =>
            console.log(
              'Service Worker registration successful with scope: ',
              registration.scope
            )
          )
          .catch((err) => console.log('Service Worker registration failed: ', err))
      }, []);
    
      return (
        <html lang="en">
          <PythonProvider>
            <body className={inter.className}>{children}</body>
          </PythonProvider>
        </html>
      );
    ***}
    

    without wrapping it with the PythonProvider again.***

    'use client'
    import { useState } from 'react'
    import { usePython } from '../../react-py/src'
    
    const Page = () => {
      const [code, setCode] = useState('input("hello:")')
      const { interruptExecution, isAwaitingInput, isLoading, isReady, isRunning, runPython, sendInput, stdout } = usePython()
    
      return (
        <>
          {isAwaitingInput && <p>INPUT A</p>}
          {isLoading && <p>Loading A</p>}
          {isReady && <p>READY A</p>}
          {isRunning && <p>RUNNING A</p>}
          <input type="text" value={code} onChange={e => setCode(e.target.value)} />
          <button onClick={() => { runPython(code) }}>RUN</button>
          <button onClick={() => { sendInput('sdfghj') }}>SEND INPUT</button>
          <button onClick={() => { interruptExecution() }}>INTERRUPT</button>
          <p>{stdout}</p>
        </>
      )
    }
    
    export default Page
    

    PythonProvider is rendered before any component

    Login or Signup to reply.
  2. Creator of react-py here.

    When using the usePython hook in your Next.js application, it is crucial to ensure that the PythonProvider component wraps around any components that rely on this hook. This is because the PythonProvider supplies the necessary context for the usePython hook to function properly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search