My objective seems quite simple, but I can’t manage to wrap my head around how Frontity and React work in this respect. I’ve looked around in the Frontity Community, in Mars-theme and on React documentation.
In the React documentation I’ve found various examples, but there seem to be differences between Frontity components and React (do I need to rewrite a component to class xxx extends React.Component
for this?). At least, it looks that way, with my pretty limited React and Frontity skills.
What I’ve done so far:
I have added my own nav menu’s, coming from the WordPress REST API (I used this topic: How to fetch Menu from wordpress?). I also added child-items for the menu-items, because only the top-level is not enough. On desktop it’s fine if these child-items appear when hovering on their parents. But on touchscreens hovering doesn’t work, so I’d like to add toggles to show and hide the child-items, at least for smartphone sized devices.
The easiest way seems (to me) to toggle a class-name on the toggle-element and add some CSS to show the child-items only when the active
class on the toggle is added. I’ve added a component which should work as a toggle and tried several ways, but I’m unable to add the class after an onClick
event.
I have also tried to do this through state.theme
, but because there could be multiple toggles in the menu, this doesn’t seem to be the right approach to me.
This is my component, cleared from all my trial & error code:
import React from "react";
import { css, connect } from "frontity";
const NavDropdownToggle = ({
state,
actions,
}) => {
return (
<span css={css`margin-left: 10px;`}>
toggle
</span>
)
};
export default connect(NavDropdownToggle);
What’s the right method to create a function to toggle a class on this element?
It feels like I’m almost there with the approach I chose, but it’s not completely working for me.
I created this component:
import React from "react";
import { css, connect } from "frontity";
const NavDropdownToggle = ({
state,
actions,
theme,
target,
}) => {
let isSubmenuOpen = state.theme.isSubmenuOpen[target];
isSubmenuOpen == null && actions.theme.toggleSubmenu[target];
return (
<span css={css`margin-left: 10px;`} submenu-open={isSubmenuOpen} onClick={actions.theme.toggleSubmenu[target]}>
toggle
</span>
)
};
export default connect(NavDropdownToggle);
And this is the actions part of index.js
:
actions: {
theme: {
...
toggleSubmenu: ({ target, state }) => {
state.theme.isSubmenuOpen[target] = (state.theme.isSubmenuOpen[target] == 'open') ? 'closed' : 'open';
}
},
},
I don’t know how to pass an argument to actions.theme.toggleSubmenu
. The target
does have a value, but when using actions.theme.toggleSubmenu(target)
I get an error Too many re-renders. React limits the number of renders to prevent an infinite loop.
and when using actions.theme.toggleSubmenu[target]
the action doesn’t run.
Solved it, trialling and erroring my way through…
I removed the state.action
and modified the component to this:
import React from "react";
import { css, connect } from "frontity";
const NavDropdownToggle = ({
state,
actions,
theme,
targetid,
}) => {
state.theme.isSubmenuOpen[targetid] = (state.theme.isSubmenuOpen[targetid] == null) ? 'closed' : state.theme.isSubmenuOpen[targetid];
console.log(targetid);
const toggleSubmenu = ( targetid ) => {
state.theme.isSubmenuOpen[targetid] = (state.theme.isSubmenuOpen[targetid] == 'closed') ? 'open' : 'closed';
}
return (
<span css={css`margin-left: 10px;`} submenu-open={state.theme.isSubmenuOpen[targetid]} onClick={() => toggleSubmenu(targetid)}>
toggle
</span>
)
};
export default connect(NavDropdownToggle);
The only thing I need in my index.js
is the following:
const marsTheme = {
...
state: {
theme: {
...
isSubmenuOpen: {},
...
},
},
...
};
export default marsTheme;
I’m not confident that this is the best approach, but at least it’s working.
Hi @dominique
Great that you eventually got to a solution. Regarding your query about class-based React components, there used to be an advantage to using them in order to use setState
, but since React 16.8 you can use React hooks in functional components. I don’t think you need to use the class syntax for declaring components in a Frontity theme. See this brief article: https://medium.com/@Zwenza/functional-vs-class-components-in-react-231e3fbd7108