craft.js
craft.js copied to clipboard
Why can't we pass local state Function from parent to child component using `<Element/>` ?
While creating a component component like Dropdown
, there is use case where we define local useState
variable and its func in the parent component and want to pass it as prop to its child component, which we achieve easily in normal React Component.
export const DropDown = () => {
const { connectors: { connect },} = useNode();
const {enabled} = useEditor((state) => ({ enabled: state.options.enabled,}));
const [isOpen, setIsOpen] = useState(false);
const toggleClick = () => {
if (!enabled) {
setIsOpen(!isOpen);
}
};
return (
<div className={props.className} ref={connect} onClick={toggleClick}>
<Element canvas id="wo" is={DropDownHead}>
<Text {...props.textComponent} text={props.text}/>
<Text
{...props.textComponent}
className="material-icons"
text={props.iconText}
/>
</Element>
{isOpen && (
<Element canvas id="xv" is={DropDownContent} >
</Element>
)}
</div>
);
};
The above is code for the Dropdown
component, but there is a flaw in above code i.e. when click on <Content/>
component, Dropdown
will not show its content, which we don't want. We that control(or onClick
eventListener) to be their in DropDownHead
component.
<Element canvas id="wo" is={DropDownHead} isOpen={isOpen} setIsOpen={setIsOpen}>
In above code, if we could pass local state variable and its Function as props to DropDownHead
component. then we would create toggleClick
function within DropDownHead
component as below 👇🏼
export const DropDownHead = ({ children, isOpen, setIsOpen, ...props }) => {
props = {
...dropDownHeadDefaultProps,
...props,
};
const toggleClick = () => {
if (!enabled) {
setIsOpen(!isOpen);
}
};
const {
connectors: { connect },
} = useNode();
return (
<div ref={connect} className={props.className} onClick={toggleClick}>
{children}
</div>
);
};
But I am only accessing isOpen
not setIsOpen
func,
Why is it so ? Then what will be the solution in order to achieve the above explained feature ????
When you use <Element />
- you're creating/referencing a Craft Node, and Nodes are serialisable. We don't currently allow functions to be props of Nodes since we can't serialise functions.
We could potentially allow a special way to pass these sort of props for Linked Nodes so that these props won't be added to the corresponding Node, but will just be passed over to the underlying React Component:
<Element id="..." is={Button} $onClick={...} />
// $onClick will be passed to the Button component, but won't exist in the Button Node
But will need to think about this more, since this will only work for Linked Nodes and not for the child Nodes.
In your example, if you really need it to work they way you want it to - you can either move the setOpen
function to a parent element outside of the Linked Node or manually add an event listener to the <div>
in the DropdownHead
component from the parent component that will call setIsOpen