I am writing a component with react typescript, but when I am trying to use it, it kept saying there is no exported member
here is my component file:
import type { FunctionComponent } from "react";
interface TitleProps{
title: string;
subtitle: string;
}
const Title: FunctionComponent<TitleProps> = ({title, subtitle}) => {
return (
<>
<h1>{title}</h1>
<h2>{subtitle}</h2>
</>
);
};
export default Title;
and here is the page I tried to use this component:
import { Title } from "#neuralbertatech/react";
import Head from "next/head";
import type { NextPage } from "next";
const Home: NextPage = () => {
return (
<>
<Head>
<title>Test</title>
</Head>
<main>
<Title title="big title" subtitle="small title" />
</main>
</>
);
};
export default Home;
here is the error:
'''
Module '"#neuralbertatech/react"' has no exported member 'Title'.ts(2305)
'''
and the Title.tsx is in this Module #neuralbertatech/react for sure.
Related
I'm using Sanity in a project and came across an error when I tried to pass props to a component
that says: "Type 'Card[]' is missing the following properties from type 'Card': _type, title, image, description, and 4 more." Card in this context is one of my schemas for Sanity that I created. When I run my web app, I also get: "SyntaxError: Unexpected token < in JSON at position 0" I'm trying to figure out why my fetching data won't work.
I've checked my type definition file, my fetch functions etc to make sure that everything connected correctly and and I didn't have any spelling or importing errors. I've also tried restarting my server. At the bottom of my index page, i'm using a getStaticProps async function. When I comment it out, my app runs, so the problem has something to do with that.
my code:
Index:
import type { GetStaticProps} from 'next';
import Head from 'next/head'
import Image from 'next/image'
import React from 'react'
import Header from 'components/Header'
import Hero from 'components/Hero'
import Middle from 'components/Middle'
import Chapters from 'components/Chapters'
import Footer from 'components/Footer'
import {Card, CardList, Chapter, Banner, Pages, Summary, SlideCard} from "typings"
import { fetchCard} from 'utils/fetchCard'
import { fetchCardList} from 'utils/fetchCardList'
import {fetchChapter} from 'utils/fetchChapter'
import {fetchBanner} from 'utils/fetchBanner'
import { fetchPages} from 'utils/fetchPages'
import { fetchSummary} from 'utils/fetchSummary'
import { fetchSlideCard} from 'utils/fetchSlideCard'
type Props = {
card: Card[];
cardList: CardList[];
chapter: Chapter[];
banner: Banner[];
pages: Pages[];
summary: Summary[];
slideCard: SlideCard[];
}
export default function Home({card, cardList, chapter, banner, pages, summary, slideCard}: Props ) {
return (
<>
<Head>
<title>Shonen Jump Plus 2</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="max-w-screen-2xl mx-auto">
<div>
<Header />
<Hero card={card}/>
<Middle />
<Chapters />
<Footer />
{/* Hero Slides */}
{/* Four Featured */}
{/* Latest Chapters */}
</div>
</main>
</>
)
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const card: Card[] = await fetchCard();
const cardList: CardList[] = await fetchCardList();
const chapter: Chapter[] = await fetchChapter();
const banner: Banner[] = await fetchBanner();
const pages: Pages[] = await fetchPages();
const slideCard: SlideCard[] = await fetchSlideCard();
const summary: Summary[] = await fetchSummary();
return {
props: {
card,
cardList,
chapter,
banner,
pages,
slideCard,
summary,
},
revalidate: 2,
};
};
Type Definitions:
interface SanityBody {
_createdAt: string;
_id: string;
_rev: string;
_updatedAt: string;
}
export interface Image extends SanityBody {
_type:"image";
asset: {
_ref: string;
_type: "reference"
};
}
export interface Card extends SanityBody {
_type: "card";
title: string;
image: Image;
description:Text;
}
export interface Banner extends SanityBody {
_type: "banner";
title: string;
image: Image;
}
export interface Pages extends SanityBody {
_type: "pages"
page1: Image;
}
export interface CardList extends SanityBody {
_type: "cardList"
thumbnail:Image;
title:string;
author:string;
chapter:string;
subtitle:string;
date:string;
}
export interface SlideCard extends SanityBody {
_type: "slideCard"
image:Image;
title:string;
chapter:string;
}
export interface Summary extends SanityBody {
_type: "summary"
title:string;
author:string;
description:Text;
}
export interface Chapter extends SanityBody {
_type: "chapter"
title:string;
date:string;
}
card schema:
export default {
name: 'card',
title: 'Card',
type: 'document',
fields: [
{
name: 'thumbnail',
title: 'Thumbnail',
type: 'image',
},
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'text',
},
],
}
getCard:
fetching data on the front-end
//Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next";
import {groq} from "next-sanity";
import {sanityClient} from "sanity";
import { Card } from "typings";
const query = groq`
*[_type == "card"]
`
type Data = {
card: Card[];
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const card: Card[] = await sanityClient.fetch(query);
res.status(200).json({ card })
}
fetchCard:
fetching data on the back-end
import {Card} from "typings";
export const fetchCard = async() => {
const res = await fetch (`${process.env.NEXT_PUBLIC_BASE_URL}/api/getCard`);
const data = await res.json();
const card: Card[] = data.card;
return card;
};
I have a list of photos, fetched from this url https://picsum.photos/v2/list.
In this list there is slug that should be extracted, for example https://unsplash.com/photos/_h7aBovKia4.
Here is fetch thing I used
import React, {Component} from 'react';
import '../App.css';
import ImageList from "./ImageList";
class App extends Component {
constructor() {
super();
this.state = {
images: []
};
}
componentDidMount() {
fetch("https://picsum.photos/v2/list")
.then(res => res.json())
.then(data => {
this.setState({ images: data });
})
.catch(err => {
console.log('Error happened during fetching!', err);
});
}
render() {
return (
<div className="container">
<h2 className="title">Images list</h2>
<ImageList data={this.state.images}/>
</div>
)
}
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
And here is ImageList Component
import React from "react";
import Image from "./Image";
const ImageList = props => {
const results = props.data;
let images = results.map(image => <Image url={image.url} key={image.id}/>);
return (
<ul className="img-list">{images}</ul>
);
};
export default ImageList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
How can I get that slug from each photo url? without it, images aren't showing in browser, just their alts
UPD. Image Component
import React from "react";
const Image = props => {
return (
<li className="image-wrap">
<img src={props.url} alt="Something went wrong"/>
</li>
)
}
export default Image;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
You have to use download_url property, not url.
The url points to a Unsplash page with comments, site interface etc. The download_url however is a direct link to the image.
I was egzecuting tutorial:
CLICK
And I am getting error: this.props.data is undefined.
I was implementing the tutorial in my test application, where I was testing also various React tools, so I have not copy-pasted it in 100%. I am using ASP.NET Core MVC and React, own architecture (for test application) and I did not installed all npm's from the tutorial. But I belive, that it is syntax or architecture problem. I am guessing, that calling server's data is corrupted somehow in app.js or CommentBox.js.
Error from console:
TypeError: this.props.data is undefined[Więcej informacji] bundle.js line 541 > eval:45:17
The above error occurred in the <CommentList> component:
in CommentList (created by CommentBox)
in div (created by CommentBox)
in CommentBox (created by App)
in div (created by App)
in div (created by App)
in App
Consider adding an error boundary to your tree to customize error handling behavior.
react-dom.development.js:14226
[Przełącz szczegóły wiadomości] TypeError: this.props.data is undefined[Więcej informacji]
Main app.js file that returns to index.js:
(...)
return (
<div className="App">
<div className="App-header">
Welcome to React!
<AddProject addProject={this.handleAddProject.bind(this)}/>
<Projects onDelete={this.handleDeleteProject.bind(this)} projects={this.state.projects} />
<CommentBox url="/comments" pollInterval={2000}/>
</div>
</div>
);
(...)
In my component folder all parent and children files:
CommentBox.js:
import React, { Component } from 'react';
import $ from 'jquery';
import uuid from 'uuid';
import CommentList from '../components/CommentList';
import CommentForm from '../components/CommentForm';
class CommentBox extends React.Component {
constructor(props) {
super(props);
this.state = { data: this.props.initialData };
}
loadCommentsFromServer() {
const xhr = new XMLHttpRequest();
xhr.open('get', this.props.url, true);
xhr.onload = () => {
const data = JSON.parse(xhr.responseText);
this.setState({ data: data });
};
xhr.send();
}
componentDidMount() {
this.loadCommentsFromServer();
window.setInterval(() => this.loadCommentsFromServer(), this.props.pollInterval);
}
render() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm/>
</div>
);
}
}
export default CommentBox;
CommentList.js:
import React, { Component } from 'react';
import $ from 'jquery';
import uuid from 'uuid';
import Comment from '../components/Comment';
class CommentList extends React.Component {
render() {
var commentNodes = this.props.data.map(function (comment) {
return (
<Comment name={comment.name} key={comment.productID}>
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
}
export default CommentList;
Comment.js:
import React, { Component } from 'react';
import $ from 'jquery';
import uuid from 'uuid';
class Comment extends React.Component {
rawMarkup() {
const md = new (global.Remarkable || window.Remarkable)();
const rawMarkup = md.render(this.props.children.toString());
return { __html: rawMarkup };
}
render() {
return (
<div className="comment">
<h2 className="commentName">
{this.props.name}
</h2>
{this.props.children}
</div>
);
}
}
export default Comment;
First, way too much code. Try to be as concise as possible.
Your issue is that this.state.data in CommentBox is undefined / null initially. Make sure that you're passing the initialData prop into CommentBox or handling the null case in CommentList
var commentNodes = (this.props.data || []).map(function (comment) {
return (
<Comment name={comment.name} key={comment.productID}>
</Comment>
);
});
I was trying to implement a News App. It should show a list of news headlines on start with thumbnail image and description and then on clickinh the url should be opened in browser. But, i am stuck on halfway getting a Type Error.
Here are the codes of my NewsList and NewsDetail files.
NewsList.js
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import NewsDetail from './NewsDetail';
class NewsList extends Component {
constructor(props) {
super(props);
this.state = {
news: []
};
}
//state = {news: []};
componentWillMount() {
axios.get('https://newsapi.org/v2/top-headlines?country=in&apiKey=MYAPIKEY')
.then(response => this.setState({news: response.data }));
}
renderNews() {
return this.state.news.map(newsData =>
<NewsDetail key={newsData.title} newsData={newsData} />
);
}
render() {
console.log("something",this.state);
return (
<ScrollView>
{this.renderNews()}
</ScrollView>
);
}
}
export default NewsList;
NewsDetail.js
import React from 'react';
import { Text, View, Image, Linking } from 'react-native';
import Card from './Card';
import CardSection from './CardSection';
import Button from './Button';
import NewsList from './NewsList';
const NewsDetail =({ newsData }) => {
const { title, description, thumbnail_image, urlToImage, url } = newsData;
const { thumbnailStyle,
headerContentStyle,
thumbnailContainerStyle,
headerTextStyle,
imageStyle } =styles;
return(
<Card>
<CardSection>
<View>
<Image
style={thumbnailStyle}
source={{uri: urlToImage}}
/>
</View>
<View style={headerContentStyle}>
<Text style={headerTextStyle}>{title}</Text>
<Text>{description}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={imageStyle}
source={{uri:urlToImage}}
/>
</CardSection>
<CardSection>
<Button onPress={() =>Linking.openURL(url)} >
ReadMore
</Button>
</CardSection>
</Card>
);
};
export default NewsDetail;
StackTrace of the Error i am getting
TypeError: this.state.news.map is not a function
This error is located at:
in NewsList (at App.js:11)
in RCTView (at View.js:78)
in View (at App.js:9)
in App (at renderApplication.js:35)
in RCTView (at View.js:78)
in View (at AppContainer.js:102)
in RCTView (at View.js:78)
in View (at AppContainer.js:122)
in AppContainer (at renderApplication.js:34) NewsList.renderNews
NewsList.js:21:31 NewsList.proxiedMethod
createPrototypeProxy.js:44:29 NewsList.render
NewsList.js:31:18 NewsList.proxiedMethod
createPrototypeProxy.js:44:29 finishClassComponent
ReactNativeRenderer-dev.js:8707:30 updateClassComponent
ReactNativeRenderer-dev.js:8674:11 beginWork
ReactNativeRenderer-dev.js:9375:15 performUnitOfWork
ReactNativeRenderer-dev.js:11771:15 workLoop
ReactNativeRenderer-dev.js:11839:25 Object.invokeGuardedCallback
ReactNativeRenderer-dev.js:39:9
App.js
import React from 'react';
import { AppRegistry, View } from 'react-native';
import Header from './header';
import NewsList from './NewsList';
//create component
const App = () => {
return(
<View style={{ flex:0 }}>
<Header headerText={'Headlines'} />
<NewsList />
</View>);
}
export default App;
AppRegistry.registerComponent('news', () => App);
The error you're getting - TypeError: this.state.news.map is not a function, means that news is not an array.
By checking your api response you should do:
this.setState({news: response.data.articles }).
You can actually go to https://newsapi.org/v2/top-headlines?country=in&apiKey="MY_API_KEY" in the browser or use a tool like curl or Postman to check what the response is. The data response is an object, but you need an array. articles is most likely the property you are after.
You may also want to check that this is an array and update what is displayed appropriately.
.then(response => {
const news = response.data.articles;
if (Array.isArray(news)) {
this.setState({ news });
} else {
this.setState({ errorMessage: 'Could not load any articles' });
}
});
I'm using jest to test a component with a <Link> from react-router v4.
I get a warning that <Link /> requires the context from a react-router <Router /> component.
How can I mock or provide a router context in my test? (Basically how do I resolve this warning?)
Link.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import { Link } from 'react-router-dom';
test('Link matches snapshot', () => {
const component = renderer.create(
<Link to="#" />
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
The warning when the test is run:
Warning: Failed context type: The context `router` is marked
as required in `Link`, but its value is `undefined`.
You can wrap your component in the test with the StaticRouter to get the router context into your component:
import React from 'react';
import renderer from 'react-test-renderer';
import { Link } from 'react-router-dom';
import { StaticRouter } from 'react-router'
test('Link matches snapshot', () => {
const component = renderer.create(
<StaticRouter location="someLocation" context={context}>
<Link to="#" />
</StaticRouter>
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Have a look at the react router docs about testing
I had the same issue and using StaticRouter would still require the context which needed more configuration to have it available in my test, so I ended up using the MemoryRouter which worked very well and without any issues.
import React from 'react';
import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom';
// SampleComponent imports Link internally
import SampleComponent from '../SampleComponent';
describe('SampleComponent', () => {
test('should render', () => {
const component = renderer
.create(
<MemoryRouter>
<SampleComponent />
</MemoryRouter>
)
.toJSON();
expect(component).toMatchSnapshot();
});
});
The answer of #Mahdi worked for me! In 2023 if you want to test a component that includes <Link> or <NavLink>, we just need to wrap it with the <MemoryRouter> in the test file:
// App.test.js
import { render, screen } from "#testing-library/react";
import MyComponent from "./components/MyComponent";
import { MemoryRouter } from "react-router-dom"; // <-- Import MemoryRouter
test("My test description", () => {
render(
<MemoryRouter> // <-- Wrap!
<MyComponent />
</MemoryRouter>
);
});
my test like this:
import * as React from 'react'
import DataBaseAccout from '../database-account/database-account.component'
import { mount } from 'enzyme'
import { expect } from 'chai'
import { createStore } from 'redux'
import reducers from '../../../reducer/reducer'
import { MemoryRouter } from 'react-router'
let store = createStore(reducers)
describe('mount database-account', () => {
let wrapper
beforeEach(() => {
wrapper = mount(
< MemoryRouter >
<DataBaseAccout store={store} />
</MemoryRouter >
)
})
afterEach(() => {
wrapper.unmount()
wrapper = null
})
})
but I don't konw why MemoryRouter can solve this。
Above solutions have a common default defact:
Can't access your component's instance! Because the MemoryRouter or StaticRouter component wrapped your component.
So the best to solve this problem is mock a router context, code as follows:
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
describe('YourComponent', () => {
test('test component with react router', () => {
// mock react-router context to avoid violation error
const context = {
childContextTypes: {
router: () => void 0,
},
context: {
router: {
history: createMemoryHistory(),
route: {
location: {
hash: '',
pathname: '',
search: '',
state: '',
},
match: { params: {}, isExact: false, path: '', url: '' },
}
}
}
};
// mount component with router context and get component's instance
const wrapper = mount(<YourComponent/>, context);
// access your component as you wish
console.log(wrapper.props(), wrapper.state())
});
beforeAll(() => {
configure({ adapter: new Adapter() });
});
});