million
                                
                                
                                
                                    million copied to clipboard
                            
                            
                            
                        bug: Not working on Nextjs 13 app-directory
Trying to use million on a Dialog component on nextjs13 with app directory.
Here's the next.config.mjs
import million from "million/compiler"
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
}
export default million.next(nextConfig);
And heres is the component
import React, { useState } from "react"
import { block } from "million/react"
import { Dialog, Stack, Typography } from "@mui/material"
import { FileWithPath, useDropzone } from "react-dropzone"
import { PrimaryButton } from "../../buttons/primary-button"
import { SecondaryButton } from "../../buttons/secondary-button"
import styles from "./index.module.scss"
import { useDispatch } from "react-redux"
import { AppDispatch, RootState } from "../../../lib/redux/store"
import { uploadPDFS } from "../../../lib/redux/actions/async"
import { useSelector } from "react-redux"
function Component() {
  const [magicModeDialogOpen, setMagicModeDialogOpen] = useState(false)
  const [error, setError] = useState("")
  const [files, setFiles] = useState<any>()
  const dispatch = useDispatch<AppDispatch>()
  const { userData } = useSelector((state: RootState) => state.centralProjectData)
  const onDrop = React.useCallback((acceptedFiles: FileWithPath[]): void => {
    if (acceptedFiles.length > 4) {
      setError("You can only add up to 4 articles")
      setTimeout(() => {
        setError("")
      }, 4000)
      return
    }
    if (acceptedFiles.some((f: any) => f.type != "application/pdf")) {
      setError("Only .pdf files are accepted")
      setTimeout(() => {
        setError("")
      }, 4000)
      return
    }
    setFiles(acceptedFiles)
  }, [])
  const handleUploadFiles = () => {
    console.log(files)
    dispatch(uploadPDFS({ userId: userData.userId, files }))
  }
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
  const handleDropzoneText = ({ isDragActive, error, files }: { isDragActive: boolean, error: string, files: boolean }) => {
    if (isDragActive) {
      return <strong>Drop it like its hot 🔥</strong>
    }
    if (error) {
      return <Typography variant="caption" color="error"><strong>{error}</strong></Typography>
    }
    if (files) {
      return <strong>Click on Upload files to start loading</strong>
    }
    return "Drag and Drop your articles here"
  }
  return (
    <>
      <Stack gap={1} className={styles.gradientBox} sx={{ p: "16px 0", border: "1px solid #e7e7e7", borderRadius: '16px' }} justifyContent="center" alignItems='center'>
        <Typography variant="caption">
          Add articles to<br />✨<strong>Magic Mode</strong>
        </Typography>
        <PrimaryButton onClick={() => setMagicModeDialogOpen(true)}>Add articles</PrimaryButton>
      </Stack>
      <Dialog open={magicModeDialogOpen} onClose={() => setMagicModeDialogOpen(false)}>
        <Stack gap={1} sx={{ p: 4, maxWidth: "500px" }}>
          <Typography variant="h6">
            Add articles to ✨<strong>Magic Mode</strong>
          </Typography>
          <Typography variant="caption" >
            Add up to 4 articles to automatically generate suggestions tailored to a specific scientific writing style or subject. <strong>Up to 4 .pdf files are allowed.</strong>
          </Typography>
          <Stack className={styles.dropzone} {...getRootProps()} >
            <input {...getInputProps()} accept="application/pdf" />
            <Typography variant="caption">
              {handleDropzoneText({ isDragActive, error, files: Boolean(files) })}
            </Typography>
          </Stack>
          <Stack direction='row' justifyContent='space-between' alignItems='center' >
            <SecondaryButton disabled={!files} onClick={() => setFiles("")}>Cancel</SecondaryButton>
            <PrimaryButton disabled={!files} onClick={handleUploadFiles}>Upload files</PrimaryButton>
          </Stack>
        </Stack>
      </Dialog>
    </>
  )
}
const MagicModeDialog = block(Component)
export default MagicModeDialog;
And the error
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
The error points specifically to the useState hooks.
Is this expected?
Good job! Love these projects, wish I had the intelligence to do something like this.
Ah, there are several problems here. Currently Million.js is limited to "deterministic" returns, so no early / conditional returns of different shape. Furthermore, I'm not sure if mui components can be optimized in this case.
I think in your case it would be best to try optimizing at a more granular level
I think one area we can improve on this is actually useful errors. Something to invest in
Granular level you mean any component inside the return? Like a separate component just for the dropzone? Also, the problem might be in the onDrop function that has conditionals?
I will play around with it and see how I can use it on my current project. Let me know if I can help you in any way!
Yep, exactly.
Any updates?
I think you should use this import instead:
import { block } from "million/next"
                                    
                                    
                                    
                                
Ah, there are several problems here. Currently Million.js is limited to "deterministic" returns, so no early / conditional returns of different shape. Furthermore, I'm not sure if mui components can be optimized in this case.
I think in your case it would be best to try optimizing at a more granular level
So wrapping the App using block is useless if it uses a component that violates the Million.js Rules of Blocks inside it?
Does million.js work only with client site components?
Hey Do you have some updates related to million and mui components?
I think you should use this import instead:
import { block } from "million/next"
I don't think that exists
Module not found: Package path ./next is not exported from package \node_modules\million
                                    
                                    
                                    
                                
@emrekardaslar yes @igor90 not yet @sam-hieken import from million/react
closing for inactivity. please open a new issue w/ a reproduction if you have a separate issue
Thanks @aidenybai for the answers. But how about this:
Yes, it would
I am facing the same basic issue, any help would be appreciated!
Hey i am facing the same issue and i am using Shadcn ui, any help would be appreciated