Using mdx-bundler, can I not import a file which imports another file?
Right now, in my .mdx file I do:
import MyComponent from './MyComponent'
This is my *mdx* file.
<MyComponent />
This works, when <MyComponent /> looks like this:
const MyComponent = () => {
return <div>Hello</div>
}
export default MyComponent
However, once I import something, it will fail. So when I change <MyComponent /> to this:
import AnotherBasicComponent from './AnotherBasicComponent'
const MyComponent = () => {
return <div>
<AnotherBasicComponent />
</div>
}
export default MyComponent
I get:
SyntaxError: Unexpected token '<'
at new Function ()
at getMDXExport (/Users/anton/projects/superdoo/node_modules/.pnpm/mdx-bundler#9.2.1_esbuild#0.15.18/node_modules/mdx-bundler/dist/client.js:44:14)
at getMDXComponent (/Users/anton/projects/superdoo/node_modules/.pnpm/mdx-bundler#9.2.1_esbuild#0.15.18/node_modules/mdx-bundler/dist/client.js:24:21)
Related
I'm new to React and am working on a small project. I'm trying to figure out why React won't read the data from my dataArray.js file. It comes up undefined when I console.log it. I made sure the data was being exported, the data was connected to the App.js file, and I have the data listed in the state.
I'm stumped as to what else to try.
import "./styles.css";
import { receiptsData } from "./dataArray";
import { Component } from "react";
import Receipt from "./components/Receipt";
class App extends Component {
state = {
receiptsData
};
render() {
console.log(receiptsData);
return (
<div className="App">
<Receipt receipts={this.state.receiptsData} />
</div>
);
}
}
export default App;
I have a copy on condesandbox.io: https://codesandbox.io/s/korillaapp-0pm5y3
I know I'm getting other errors as well, but I think it's tied to not being able to read the data from the dataArray.js file.
You have a default export in dataArray.js and named import in App.js.
So or do export const receiptsData = ... in dataArray.js, or import it as import receiptsData from "./dataArray"; in App.js
You exported your array as default export, so it should be imported like this :
import receiptsData from "./dataArray";
Or change your export like this :
export const receipts = [...]
1) Replace Receipt.js with below code
import ReceiptItem from "./ReceiptItem";
const Receipt = (props) => {
const { receipts } = props;
const receiptList = receipts.map((receipt, idx) => {
return(<div>
<ReceiptItem receipt={receipt} key={idx} />
</div>);
});
return (
<div>{receiptList}</div>
)
};
export default Receipt;
2) Add below line of code in the last in ReceiptItem.js
export default ReceiptItem;
3) You have default export receiptsData from dataArray.js so use receiptsData with {} in App.js
Export and import of App seem alright. The error must be due to some mixing of names. This is my first react application. I have scoured various StackOverflow posts with the same error but I couldn't extract helpful insight from them. So, please be a bit elaborate.
Error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. 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 App.
Index.js :
import App from './App';
ReactDOM.render(<App /> , document.getElementById('root'));
App.jsx :
import React from 'react';
import { StreamChat } from 'stream-chat';
import { Chat } from 'stream-chat-react';
import Cookies from 'universal-cookie';
import { ChannelListContainer, ChannelContainer } from './components';
const App = () => {
return (
<div className="app__wrapper">
<Chat client={client} theme="team light">
<ChannelListContainer
/>
<ChannelContainer
/>
</Chat>
</div>
);
}
export default App;
index.js in ./components:
export { default as ChannelContainer } from './ChannelContainer';
export { default as ChannelListContainer } from './ChannelListContainer';
Because of you're using:
export { default as ChannelContainer } from "./ChannelContainer";
export { default as ChannelListContainer } from "./ChannelListContainer";
You need to export ChannelContainer from ./ChannelContainer like:
const ChannelListContainer = () => {
return <>ChannelListContainer</>;
};
export default ChannelListContainer;
And export ChannelListContainer from ./ChannelListContainer like:
const ChannelContainer = () => {
return <>ChannelContainer</>;
};
export default ChannelContainer;
Here's the sample based on your structure:
We can extract the Vue component's Props into docs by writing this code in MDX
import { Props } from "#storybook/addon-docs/blocks";
import MyComponent from "./index.vue";
<Props of={MyComponent} />;
How can I achieve the same thing in regular stories?
import MyComponent from "./index.vue";
import { Props } from "#storybook/addon-docs/blocks";
// I don't know where to put `Props`
export default {
title: "MyComponent",
};
export const MyComponentStory = () => ({
components: { MyComponent },
template: `
<MyComponent />
`,
});
What should I do to achieve the same thing?
I was trying to get the queries from my url pattern like localhost:3000/post?loc=100 by using useRouter() from "next/router" and fetching some data using that id from my server. It worked when I used it in a Stateless Functional Component.
But the page showing "Invalid hook call" then. I tried calling getInitalProps() of a Stateless Functional Component, but it didn't work there either and showed the same error.
Is there any rule to use this method?
I was developing a front-end using React Library and Next.js Framework.
constructor(props) {
this.state = {
loc: useRouter().query.loc,
loaded: false
};
}
Hooks can be used only inside functional components, not inside classes. I would recommend to use withRouter HOC as per next.js documentation:
use the useRouter hook, or withRouter for class components.
Or see From Classes to Hooks if you want to switch to hooks.
In general, it's possible to create a wrapper functional component to pass custom hooks into class components via props (but not useful in this case):
const MyClassWithRouter = (props) => {
const router = useRouter()
return <MyClass {...props} router={router} />
}
class MyClass...
constructor(props) {
this.state = {
loc: props.router.query.loc,
loaded: false
};
}
withRouter example
https://stackoverflow.com/a/57029032/895245 mentioned it, but a newbie like me needed a bit more details. A more detailed/direct description would be:
Function component:
import { useRouter } from "next/router";
export default function Post() {
const router = useRouter();
return (
<div>{ router.query.id }</div>
)
}
Class component equivalent:
import { withRouter } from 'next/router'
import React from "react";
export default withRouter(class extends React.Component {
render() {
return (
<div>{ this.props.router.query.id }</div>
)
}
})
I tested this out more concretely as follows. First I took vercel/next-learn-starter/basics-final/pages/posts/[id].js and I hacked it to use the router:
diff --git a/basics-final/pages/posts/[id].js b/basics-final/pages/posts/[id].js
index 28faaad..52954d3 100644
--- a/basics-final/pages/posts/[id].js
+++ b/basics-final/pages/posts/[id].js
## -4,13 +4,17 ## import Head from 'next/head'
import Date from '../../components/date'
import utilStyles from '../../styles/utils.module.css'
+import { useRouter } from "next/router"
+
export default function Post({ postData }) {
+ const router = useRouter();
return (
<Layout>
<Head>
<title>{postData.title}</title>
</Head>
<article>
+ <div>router.query.id = {router.query.id}</div>
<h1 className={utilStyles.headingXl}>{postData.title}</h1>
<div className={utilStyles.lightText}>
<Date dateString={postData.date} />
Then, I ran it as:
git clone https://github.com/vercel/next-learn-starter
cd next-learn-starter
git checkout 5c2f8513a3dac5ba5b6c7621d8ea0dda881235ea
cd next-learn-starter
npm install
npm run dev
Now when I visit: http://localhost:3000/posts/ssg-ssr I see:
router.query.id = ssg-ssr
Then I converted it to the class equivalent:
import Layout from '../../components/layout'
import { getAllPostIds, getPostData } from '../../lib/posts'
import Head from 'next/head'
import Date from '../../components/date'
import utilStyles from '../../styles/utils.module.css'
import { withRouter } from 'next/router'
import React from "react"
export default withRouter(class extends React.Component {
render() {
return (
<Layout>
<Head>
<title>{this.props.postData.title}</title>
</Head>
<article>
<div>router.query.id = {this.props.router.query.id}</div>
<h1 className={utilStyles.headingXl}>{this.props.postData.title}</h1>
<div className={utilStyles.lightText}>
<Date dateString={this.props.postData.date} />
</div>
<div dangerouslySetInnerHTML={{ __html: this.props.postData.contentHtml }} />
</article>
</Layout>
)
}
})
export async function getStaticPaths() {
const paths = getAllPostIds()
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }) {
const postData = await getPostData(params.id)
return {
props: {
postData
}
}
}
and everything seemed to be unchanged.
Tested on Next.js 10.2.2.
I am coming from a vue.js background and I have just recently started looking into react.
I have a component: PageContent.jsx and I wish to use it without constantly having to import it to be able to use it inside the render function (JSX).
In vue it is possible to globalise a component using:
Vue.component(componentName, componentObject)
Is there anything similar in react?
Hmm, there isn't any kind of "global" component in React. Each component has to be imported or passed as a prop. You have a few options if you want to avoid adding an import to each file though:
1) Create a Higher Order Component that renders the PageContent and the wrapped component.
import PageContent from './PageContent';
const withPageContent = WrappedComponent => {
return class extends React.Component {
render () {
return (
<PageContent>
<WrappedComponent />
</PageContent>
)
}
}
};
export default withPageContent;
// Usage
import withPageContent from './withPageContent';
class MyComponent extends React.Component {
render () {
return (
<div>
I'm wrapped in PageContent!
</div>
)
}
}
export default withPageContent(MyComponent);
2) Pass PageContent as a prop to a component:
import PageContent from './PageContent';
export default class App extends React.Component {
render() {
return (
<React.Fragment>
<Child1 content={PageContent} />
<Child2 content={PageContent} />
</React.Fragment>
)
}
}
// Usage
export default class Child1 extends React.Component {
render () {
const PageContent = this.props.content;
return (
<PageContent>
I'm wrapped in PageContent!
</PageContent>
)
}
}
export default class Child2 extends React.Component {
render () {
const PageContent = this.props.content;
return (
<PageContent>
I'm wrapped in PageContent!
</PageContent>
)
}
}
I very much agree with Chase's answer.
Still if you need another approach you can use the context api. You can declare in the App root, or another nested components tree, a collection of components that you want to easily access.
Here is an example with the useContext hook, but hooks is not a must. The structure is the standard create-react-app structure.
The component we would like to access globally - src/deep/Header.js:
function Header() {
return (
<h1>
I am a global component
</h1>
);
}
export default Header;
The context creation - src/global-components-context.js:
import React from 'react';
const MyContext = React.createContext(null);
export default MyContext;
The grouping of the global-components - src/global-components.js:
import Header from './deep/Header';
const contextValue = {
Header,
};
export default contextValue;
The app init file - src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import MyContext from './global-components-context';
import contextValue from './global-component';
ReactDOM.render(
<MyContext.Provider value={contextValue}>
<App />
</MyContext.Provider>,
document.getElementById('root')
);
Using the component without importing it - src/App.js:
import { useContext } from 'react';
import globalComponent from './global-components-context';
function App() {
const Context = useContext(globalComponent);
return (
<div className="App">
<Context.Header />
</div>
);
}
export default App;
I think this is the most global components you can have in react. Note that you still need to import the context wherever you would like to use a global component.
Also one more disclaimer, global components are very hard to test and often to reason about. I believe that is why there is no standard solution for it in react.
Hope I could help