Reputation: 97
I am learning React and trying to implement a simple onClick button in a child Component only to get an "Invalid hook call". I've gutted a lot of my program to isolate just the problem.
Parent Component:
import React, { useState } from "react";
import Menubar from '../Menubar/Menubar'
function SortingVisualizer() {
const [arr, setArr] = useState([]);
function newArray() {
const tempArr = [];
for(let i = 0; i < 100; i++) {
tempArr.push(Math.floor(Math.random() * 100) + 5)
}
setArr(tempArr);
}
return (
<div id="main-container">
<Menubar
data={arr}
/>
</div>
)
}
export default SortingVisualizer;
Child Component in another module:
import React from "react";
import newArray from '../SortingVisualizer/SortingVisualizer'
import bubbleSort from '../algorithms/bubbleSort'
function Menubar(props) {
return(
<div id="menubar-container">
<button id="new-array-button" onClick={() => newArray()}>New Array</button> // Invalid hook error
<button id="bubble-sort-button" onClick={() => bubbleSort(props.data)}>Bubble Sort</button> // Works fine
</div>
)
}
export default Menubar;
When I run "npm ls react-dom", I only get a single version returned which should mean I do not have mismatching version problems:
`-- [email protected]
I suspect that I am breaking some hook rules but not sure which one. If I had to guess, based on another problem I saw, I think this has to do with the fact that hooks can only be used at the top level. I think that somehow my onClick for newArray is misusing that hook rule.
But something else I don't get is...shouldn't "import newArray..." be enough to use a function from another module? Isn't that how it works in plain javascript where one module can use the function of another module simply by importing/exporting?
Upvotes: 0
Views: 140
Reputation: 506
I'm not sure if this is the best solution but you can create a hook too
// useArray.js
import {useState} from "react"
const useArray = () => {
const [arr,setArray] = useState([])
function newArray() {
const tempArr = [];
for(let i = 0; i < 100; i++) {
tempArr.push(Math.floor(Math.random() * 100) + 5)
}
setArr(tempArr);
}
return {
newArray,
arr
}
}
export default useArray
even if in your example I don't understand why not to put your state in your child component since your parent doesn't use it
//Child component
import React from "react";
import bubbleSort from '../algorithms/bubbleSort'
function Menubar() {
const [arr, setArr] = useState([]);
const newArray = () => {
// ...
}
return(
<div id="menubar-container">
<button id="new-array-button" onClick={newArray}>New Array</button>
<button id="bubble-sort-button" onClick={() => bubbleSort(arr)}>Bubble Sort</button>
</div>
)
}
export default Menubar;
Upvotes: 0
Reputation: 1719
You can't import a function like that. You have to pass the function to the children component.
In the parent component
// SortingVisualizer.js
export const SortingVisualizer = () => {
const [arr, setArr] = useState([]);
const newArray = () => {
// ...
}
return (
<div id="main-container">
<Menubar data={arr} newArray={newArray} />
</div>
)
}
In the children component
// import newArray from '../SortingVisualizer/SortingVisualizer'; Remove that line
import bubbleSort from '../algorithms/bubbleSort'
const Menubar = ({ newArray }) => {
return(
<div id="menubar-container">
<button id="new-array-button" onClick={() => newArray()}>New Array</button>
<button id="bubble-sort-button" onClick={() => bubbleSort(props.data)}>Bubble Sort</button> // Works fine
</div>
)
}
Upvotes: 2
Reputation: 2282
To pass the function to the child component, you can pass it as a props
<Menubar
data={arr}
newArray={newArray}
/>
Then in the child component, you call the function from the props
const { newArray } = props;
return (
<div id="menubar-container">
<button id="new-array-button" onClick={newArray}>New Array</button>
Upvotes: 0