Unable to implement Leftnav with AppBar component in material-ui - reactjs

I am having a lot of trouble trying to implement material-ui's AppBar with Leftbar as there seems to be lots of different variations on component declaration/imported dependencies syntax and components. I can't even find proper documention on http://www.material-ui.com/ about Leftnav in the first place, all they give with Appbar is a static hamburger menu example. My code is as follows:
import React, { Component } from 'react'
import { LeftNav, AppBar} from 'material-ui'
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme'
import getMuiTheme from 'material-ui/styles/getMuiTheme'
import { Router, Route, Navigation, Link, browserHistory } from 'react-router'
export default class Header extends Component {
getChildContext() {
return {muiTheme: getMuiTheme(baseTheme)};
}
_toggleNav(){
this.refs.leftNav.toggle();
}
render() {
const data = this.props.data
const nav_items = data.globals.nav_items
//Menu item links
const menu_items = nav_items.map(( nav_item ) => {
return (
<span key={ 'key-' + nav_item.value }>
<Link to={ '/' + nav_item.value }>{ nav_item.title }</Link>
</span>
)
})
return (
<div>
<LeftNav ref='leftNav'
docked={false}
menuItems={ menu_items } />
<AppBar title="App Bar Example" onLeftIconButtonTouchTap={this._toggleNav}
isInitiallyOpen={true} />
</div>
)
}
}
Header.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
I am getting to obscure errors which explain me nothing about what am actually doing wrong:
VM15235:27 Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `Header
and:
invariant.js:38 Uncaught (in promise) Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of `Header`.(…)
Is there a way of making this more explicit?

There was a change to material-ui that renamed LeftNav to Drawer! It seems like certain docs/examples haven't been updated. So if you use Drawer you will find documentation and it should work! Here is the commit/thread from the change away from LeftNav.
https://github.com/callemall/material-ui/issues/2697

Related

Render Custom Component Inside NextJS Link

Issue:
I have a component that should redirect users to a new page on click. I want to use Next's <Link> component to take care of the route change.
However, I've noticed that the Link component refuses to render if any of its children are not standard HTML elements (e.g., <div>, <a>, ...).
In the example below, the component I want to render is an icon from the heroicons library.
MyPage.js
import Link from 'next/link'
import { ArrowSmRightIcon } from 'heroicons-react'
export default function MyPage() {
return(
<Link href='/targetPage'>
<ArrowSmRightIcon />
</Link>
)
}
Running the above renders the following error:
Error: Element type is invalid: expected a string (for built-in
components) or a class/function (for composite components) but got:
undefined.
Attempted solution:
I've found some advice online about having to create a custom component that using forwardRef. I've implemented my custom component as:
IconLink.js
import NextLink from 'next/link'
import { forwardRef } from "react";
import { ArrowSmRightIcon } from 'heroicons-react'
const IconLink = forwardRef(({ href, prefetch, replace, scroll, shallow, locale, ...props }, ref) => {
return(
<NextLink
href={href}
replace={replace}
scroll={scroll}
shallow={shallow}
locale={locale}
passHref
>
<ArrowSmRightIcon ref={ref} {...props} />
</NextLink>
)
})
export default IconLink
MyPage.js
import IconLink from './IconLink';
export default function MyPage() {
return(
<IconLink
passHref
href='/targetPage'
/>
)
}
However, I still get the same error.
What should I do render a custom child component inside Next's <Link> component?
The problem is not from the next/link, the problem is from the import, This error indicates that there is no named export "ArrowSmRightIcon" in the package heroicons-react I believe what you're looking for is ArrowSmRight
import { ArrowSmRight } from 'heroicons-react'
Plus the package is deprecated as stated by the maintainers:
This package has been deprecated
Author message:
Official Heroicons V1 released. Please use the following for future >
projects: https://www.npmjs.com/package/#heroicons/react
the currently maintained version is:
https://www.npmjs.com/package/#heroicons/react

Link returns undefined when mapping array to JSX component

The following code gives an error when I visit the page this component is rendered on:
import React from 'react'
import Layout from '../components/layout'
import SEO from '../components/seo'
import {
Divider,
Card,
Link,
} from '#blueprintjs/core'
const TagPage = ({ pageContext }) => {
const { name, description, tagsCount, questions, } = pageContext
return (
<Layout>
<SEO title={name} description={description} />
<h1>{name}</h1>
<p>{description}</p>
<Divider />
<br/><br/>
{questions.map((q) => {
return (
<>
<Link
to={`tagsQuestion-${q.id}`}
style={{
color: `inherit`,
textDecoration: `none`,
}}
>
<Card interactive='true'>
<p>{q.id}</p>
<p>{q.prompt}</p>
</Card>
</Link>
<br/>
</>
)
})}
</Layout>
)
}
export default TagPage
However if I change:
<Link to={`/question/${q.id}`}>...</Link>
into
<a href={`/question/${q.id}`} >...</a>
then the page will render and be useable without any errors.
This is the current error message I am getting:
(AppContainer, in main (at layout.js:33)) Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check the render method of `TagPage
Question:
Why can I not use the Link component in this situation?
Info:
questions is an array
TagPage is a page created in gatsby-node.js
Thanks you, for your time, feel free to ask questions as needed.
replace
import {
Divider,
Card,
Link,
} from '#blueprintjs/core'
with
import { Link } from 'gatsby'
import {
Divider,
Card,
} from '#blueprintjs/core'

Snapshot testing error: Element type is invalid: expected a string [...]

I'm trying to do some simple snapshot testing using React and Jest.
Initially I was getting this error: Invariant failed: You should not use <Link> outside a <Router>
After reading this question I updated my test and wrapped the component I'm testing in: <MemoryRouter>...</MemoryRouter>. Once I did this, I started getting a new error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. I have no idea what that means.
My test:
import React from "react";
import BookTile from "./BookTile";
import MemoryRouter from "react-router-dom";
import renderer from "react-test-renderer";
test("my test", () => {
let book = {};
const component = renderer.create(
<MemoryRouter>
<BookTile book={book} />
</MemoryRouter>
)
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
})
The component I'm testing:
import React from "react";
import {Link} from "react-router-dom";
export default function BookTile(props) {
return (
<Link to={`/book/${props.book.id}`}>
<div className="book-tile" style={{'backgroundImage': `url(${process.env.REACT_APP_API_URL}/uploads/${props.book.cover_image_file_name})`}}>
<div className='book-tile-title'>
{props.book.title}
</div>
</div>
</Link>
)
}
You are not importing memory router correctly. Here's how it should look like:
import {MemoryRouter} from 'react-router-dom'

Styled Component rendering triggers Element type error

I just installed the styled-components library and started playing with it.
However this simple example:
import React from 'react'
import styled from 'styled-components'
const Div = styled.div`background: red;`
const AlertCard = () => (
<Div>Hello World</Div>
)
export default AlertCard
And the render function:
render() {
const { fetchingAlerts, alerts } = this.props
return (
fetchingAlerts ?
<Loader /> :
<div>
<AlertFormContainer />
<div>
{alerts.length === 0 ?
<EmptyAlerts /> :
<div>
{alerts.map(alert => (
<AlertCard text="My text " />
))}
</div>
}
</div>
</div>
)
)
}
triggers this error: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
The styled component returns an object of $$typeof: Symbol(react.element)
I don't know what goes wrong
Which version of React, React-Dom and Styled-Component are you using?
Make sure that react and react-dom are >=16.3.0 with styled-component >=4.0.0
The breaking change brought upong the use of the new Context api in styled-component v4 requires react >=16.3.0
see point #2 on https://www.styled-components.com/docs/faqs#what-do-i-need-to-do-to-migrate-to-v4

React not rendering multiple components through factory function

The problem is the following, i have a factory:
import React from 'react';
export default (componentFactory) =>
{
return Component =>
{
class Factory extends React.Component
{
render()
{
let { state, props } = this;
return componentFactory({ state, props }, Component);
}
}
return Factory;
};
}
and then a simple Page component wrapper:
import React from 'react';
const Page = ({children, appState}) =>
(
<section>
{React.cloneElement(children, {appState})}
</section>
);
export default Page;
So, in order to create a HomePage, i use HomeFactory likewise:
import React from 'react';
import Factory from '../Factory';
import HeroBanner from '../Banner/HeroBanner';
const HomeFactory = ({state, props}, HomePage) =>
{
return <HomePage {...props} {...state} >
<HeroBanner />
</HomePage>;
};
export default Factory(HomeFactory);
The final code for the HomePage component that is being mounted, is then as follows:
import React from 'react';
import Page from '../Page';
import HomeFactory from '../HomeFactory';
const HomePage = ({children, appState}) =>
{
return (
<Page appState={appState}>
{children}
</Page>
);
};
export default HomeFactory(HomePage);
The problem seems to be the HomeFactory component, in which i put:
return <HomePage {...props} {...state} >
<HeroBanner />
</HomePage>;
as per example given, and this works 100% correctly, however, when i try to put multiple components in form of array or just many components nested in, like:
return <HomePage {...props} {...state} >
<HeroBanner />
<HeroBanner />
<HeroBanner />
</HomePage>;
I am getting the following error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
Basically, the Page wrapper component is getting properties passed in as children of its parent component HomePage, and these are taken from the factory method.
The question is what is happening implicitly with JSX that I cannot do the following?
In your Page component you need to use cloneElement along with Children.map when you pass multiple children (this.props.children is then a special array-like object)
See this answer: stackoverflow.com/a/38011851/3794660 for more details.

Resources