Can't render another component from another - reactjs

I am having trouble rendering another component from my current component in vs code. The error message I get is..
Type '{}' is not assignable to type 'IntrinsicAttributes &
IntrinsicClassAttributes & Readonly<{ children?: ReactNode;
}> & ...'. Type '{}' is not assignable to type
'Readonly>'.
Property 'match' is missing in type '{}'.
Here is my code..
import * as React from 'react';
import { BillList } from './BillList';
import * as ReactDOM from "react-dom";
export interface BillComponentState {
children?: React.ReactNode,
bills: BillList
}
export class BillComponent extends React.Component<BillList>{
public render() {
return <div className='container-fluid'>
<div className='row'>
<div className='col-sm-3'>
<BillList />
</div>
<div className='col-sm-9'>
{this.props.children}
</div>
</div>
</div>;
}
}
Why can't I just render my BillList which is literally rendering a list of strings from a web api on my web server?
Disclaimer: I'm very new to React
EDIT: Here is the code in BillList.tsx
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
interface BillState {
bills: Bill[],
loading: boolean
}
export class BillList extends React.Component<RouteComponentProps<{}>, BillState>
{
constructor() {
super();
this.state = { bills: [], loading: true };
fetch("api/SampleData/GetBills")
.then(response => response.json() as Promise<Bill[]>)
.then(data => {
this.setState({
bills: data,
loading: false
});
});
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: BillList.renderBillsToList(this.state.bills);
return <div className="rendered-bills">
<h1>Bills to pay</h1>
{contents}
</div>
}
public static renderBillsToList(bills: Bill[]) {
return <ul>
{bills.map((bill, i) =>
<li key={i}> {bill.name} </li>
)}
</ul>;
}
}
interface Bill {
name: string;
}
Here is the code in a public repo. Let me know if you need more debugging information from me.
https://github.com/ddeamaral/billTracker

This code sample doesn't provide enough information to tell where the error originated from. However, the React.Component first parameter accepts the components properties and you seem to be passing on a component (BillList). Also there is a BillComponentState interface defined but never used and I don't see any actual component state.
Based on this code sample I can only advise you to rename BillComponentState to BillComponentProps and pass this to the component instead of BillList.
import * as React from 'react';
import { BillList } from './BillList';
import * as ReactDOM from "react-dom";
export interface BillComponentProps {
children?: React.ReactNode,
bills: BillList
}
export class BillComponent extends React.Component<BillComponentProps>{
public render() {
return <div className='container-fluid'>
<div className='row'>
<div className='col-sm-3'>
<BillList />
</div>
<div className='col-sm-9'>
{this.props.children}
</div>
</div>
</div>;
}
}
But this is just guessing since we don't know what BillList looks like.

Related

react typescript with function passed as prop, but can't access

I am making a simple toggle button with react + typescript.
I want to practice some complex feature by passing function as prop to child component.
I remember 'this.props' allows me to access all props passed to child in typescript. So if I define a function in parent, I should be able to call the function in child, right?
But I got the below error. Can someone please give me a helping hand? Thank you.
Error:
(property) React.DOMAttributes.onClick?: React.MouseEventHandler | undefined
Type '(checked: boolean) => void' is not assignable to type 'MouseEventHandler'.
Types of parameters 'checked' and 'event' are incompatible.
Type 'MouseEvent' is not assignable to type 'boolean'.ts(2322)
Code:
src/
import React from 'react';
import ReactDOM from 'react-dom';
import Switch from './Switch';
interface State {
buttonOn: boolean;
}
class App extends React.PureComponent<{}, State> {
public state: State = {
buttonOn: false,
};
onChange = (checked: boolean) => this.setState({ buttonOn: checked });
render() {
return (
<div>
<Switch
checked={this.state.buttonOn}
onChange={(checked) => this.onChange(!checked)}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app')!);
src/Switch/
import React from 'react';
import './index.css';
interface Props {
checked: boolean;
onChange: (checked: boolean) => void;
disabled?: boolean;
}
export default class Switch extends React.PureComponent<Props> {
render() {
return (
<div>
<div onClick={this.props.onChange} /> {/* error here */}
</div>
);
}
}
so you have 2 options... Either
Do it like this where this.props.onChange is being returned by the onClick lambda function. You can also wrap this in curly braces if you want
export default class Switch extends React.PureComponent<Props> {
render() {
return (
<div>
<div onClick={(e) => this.props.onChange} /> {/* error here */}
</div>
);
}
}
or;
Change your types... It's always worth hovering over a property such as onClick to understand the function signature as well as the type of arguments that are being passed in.
# src/App.tsx
import React from "react";
import Switch from "./Switch";
interface State {
buttonOn: boolean;
}
class App extends React.PureComponent<{}, State> {
public state: State = {
buttonOn: false
};
onChange = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
console.log(event);
};
render() {
return (
<div>
<Switch checked={this.state.buttonOn} onChange={this.onChange} />
</div>
);
}
}
export default App;
Then in the Switch:
# src/Switch.tsx
import React from "react";
interface Props {
checked: boolean;
onChange: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
disabled?: boolean;
}
export default class Switch extends React.PureComponent<Props> {
render() {
return (
<div>
<button onClick={this.props.onChange}> Hello world </button>
</div>
);
}
}
I wrote a Codesandbox playground here so you can test it out yourself.

Error: Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes & Pick<ClassAttributes<Layout>&Props, "ref" | "key">'

Error: Type '{ children: Element; }' has no properties in common with
type 'IntrinsicAttributes & Pick<ClassAttributes & Props,
"ref" | "key">'.
I'm new learner of reactjs with typescript and I follow the https://www.youtube.com/watch?v=8jHKBAPNtpM tutorial for learning, but things are not explained properly on this video.
Can Anyone help me for resolve this issue.
My HomePage.tsx file
import React, { Component } from "react";
import Layout from "../../components/common/layout";
import Content from "../../components/common/content";
import Home from "./../../components/home";
class HomePage extends Component {
render() {
return (
<div className="wrapper">
<Layout>
<Content title="Dashboard">
<Home />
</Content>
</Layout>
</div>
);
}
}
export default HomePage;
my Layout.tsx file
import React, { Component } from "react";
import { connect } from "react-redux";
import TopNav from "../topnav";
import Aside from "../aside";
import UserStateInterface from "../../../interfaces/UserStateInterface";
import UserService from "../../../services/UserService";
import { setUser } from "./../../../store/actions";
interface Props {
user: UserStateInterface;
setUser: typeof setUser;
}
class Layout extends Component<Props> {
async componentDidMount() {
const response = await UserService.getCurrentUserProfile();
this.props.setUser(response);
}
render() {
return (
<React.Fragment>
<TopNav />
<Aside user={this.props.user} />
{this.props.children}
</React.Fragment>
);
}
}
const mapStateToProps = (state) => {
return {
user: state.user,
};
};
export default connect(mapStateToProps, { setUser })(Layout);
my Content.tsx file
import React, { Component } from "react";
interface Props {
title: String;
}
class Content extends Component<Props> {
render() {
const { title } = this.props;
return (
<div className="content-wrapper">
<section className="content-header">
<div className="container-fluid">
<div className="row mb-2">
<div className="col-sm-6">
<h1>{title}</h1>
</div>
<div className="col-sm-6">
<ol className="breadcrumb float-sm-right">
<li className="breadcrumb-item">
<a href="/" onClick={(event) => event.preventDefault()}>
Home
</a>
</li>
<li className="breadcrumb-item active">Blank Page</li>
</ol>
</div>
</div>
</div>
</section>
<section className="content">{this.props.children}</section>
</div>
);
}
}
export default Content;
my Home.tsx file
import React, { Component } from "react";
import Card from "./../common/card";
import TopCards from "./topcards";
import TodoWrapper from "../todo/todowrapper";
class Home extends Component {
render() {
return (
<React.Fragment>
<TopCards />
<div className="row">
<div className="col-md-6">
<TodoWrapper />
</div>
<div className="col-md-5">
<Card title="Some content will come" titleIcon="ion-clipboard">
<p>Content will come.</p>
</Card>
</div>
</div>
</React.Fragment>
);
}
}
export default Home;
You need to tell react that the component is ready to accept children.
React provides a utility for exactly this. Just replace your interface Props {...} with type Props = PropsWithChildren<{...}>.
import { PropsWithChildren } from "react";
type Props = PropsWithChildren<{
user: UserStateInterface;
setUser: typeof setUser;
}>;
Example: https://codesandbox.io/s/boring-chatelet-kp5vm?file=/src/Layout.tsx

ReactJs passing methods as props from one class to the next (with typescript)

I worked with react before, but using type script I am having issues pass methods as props. I having trouble following some of the examples on the internet.
Property 'onDrawerToggle' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ companyId: string; }> & Readonly<{ children?: ReactNode; }>'. TS2322
import React from 'react';
import HeaderBar from './Header';
import SideDrawer from './SideDrawer';
import BackDrop from './BackDrop';
interface PassedProps extends React.Props<any> {
onDrawerToggle:any
}
interface MyState {
value: string
}
export default class FrontScreen extends React.Component <{},{sideDrawer:any},PassedProps>{
constructor(props: any) {
super(props);
this.state = {
sideDrawer: false
};
}
drawerToggleClickHandler() {
this.setState((prevState)=>{
this.state.sideDrawer != prevState.sideDrawer
});
}
render() {
return (
<div className="fluid-container">
<HeaderBar onDrawerToggle={this.drawerToggleClickHandler()} companyId="10"></HeaderBar>
</div>
);
}
}
I am trying to pass a method to next class, but i keep getting an error. I trying to figure this out cause i never used typescript if you could give me an example I would be able to replicate and understand it.
import React from 'react';
import { Navbar, Nav, Form, Button, FormControl } from 'react-bootstrap';
import axios from 'axios';
import ProfileButton from './ProfileButton';
interface Props {
drawerClick: () => any;
}
export default class HeaderBar extends React.Component <{companyId:string},{companyName:any},{drawerClick:any}>{
constructor(props: any) {
super(props);
this.state = {
companyName: 'load',
};
}
limitTextFilter(text:string){
if(text.length > 14) {
return text.substring(0,14);
}
return text;
}
componentDidMount() {
axios.request(
{method:'get',
url:'http://localhost:3000/company'
})
.then(res => {
this.setState({ companyName: res.data.companyName });
console.log(res)
})
}
render() {
return (
<Navbar className="cs-header-bar p-0">
<Nav className="align-middle w-100">
<Nav.Link className="text-white">
<ProfileButton onClick={this.props.drawerClick}/>
</Nav.Link>
<Nav.Link className="text-white align-self-center">
<p className="cs-link cs-company-name">{this.limitTextFilter(this.state.companyName)}
</p>
</Nav.Link>
</Nav>
</Navbar>
);
}
}
You pass the onDrawerToggle as an prop of the component HeaderBar, so you must declare the type of props of the component HeaderBar.
type Props = {
onDrawerToggle: Function
}
export default class HeaderBar extends React.Component<Props>{
...
}
By the way, you can declare the state type of your component by passing the second type param:
export default class HeaderBar extends React.Component<Props, State>{
...
}

React dynamic menu from database

so I have been trying to create dynamic menu in .net core + react environment
the problem I have been facing is basically this error message
Type '{}' is not assignable to type
'Readonly<RouteComponentProps<{}>>'.
Property 'match' is missing in type '{}'
Here is the code for
Layout.tsx
import * as React from 'react';
import { NavMenu } from './NavMenu';
export interface LayoutProps {
children?: React.ReactNode;
}
export class Layout extends React.Component<LayoutProps, NavMenu> {
public render() {
return <div className='container-fluid'>
<div className='row'>
<div className='col-sm-3'>
<NavMenu />
</div>
<div className='col-sm-9'>
{ this.props.children }
</div>
</div>
</div>;
}
}
the other file is NavMenu.tsx
import * as React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { RouteComponentProps } from 'react-router';
import * as ReactDOM from 'react-dom';
interface navMenuItems {
menuItemsList: NavMenuPages[];
loading: boolean;
}
export class NavMenu extends React.Component<RouteComponentProps<{}>, navMenuItems> {
constructor() {
super();
this.state = { menuItemsList: [], loading: true };
fetch('api/Menu')
.then(response => response.json() as Promise<NavMenuPages[]>)
.then(data => {
this.setState({ menuItemsList: data, loading: false });
});
}
public render() {
this.renderMenu(this.state.menuItemsList);
return <div></div>;
}
public renderMenu(menuItemsList: NavMenuPages[]) {
return <div className='main-nav'>
<div className='navbar navbar-inverse'>
<div className='navbar-header'>
<button type='button' className='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
<span className='sr-only'>Toggle navigation</span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
</button>
<Link className='navbar-brand' to={'/'}>ReactCrudDemo</Link>
</div>
<div className='clearfix'></div>
<div className='navbar-collapse collapse'>
<ul className='nav navbar-nav'>
{menuItemsList.map(mil =>
<li>
<NavLink to={`${mil.toLink}`} exact activeClassName='active'>
<span className='glyphicon glyphicon-home'></span> {mil.name}
</NavLink>
</li>
)}
</ul>
</div>
</div>
</div>;
}
}
export class NavMenuPages{
name: string = "";
toLink: string = "";
isShown: boolean = true;
}
remaining files are the same as this tutorial:
https://www.c-sharpcorner.com/article/asp-net-core-crud-with-reactjs-and-entity-framework-core/
You are declaring NavMenu as requiring the RouteComponentProps<{}>, which it would normally receive automatically if you call it via <Route>, but you are calling it directly without passing the required props. Since NavMenu does not use any of the RouteComponentProps, you can just change the props type. Replace:
export class NavMenu extends React.Component<RouteComponentProps<{}>, navMenuItems>
with:
export class NavMenu extends React.Component<{}, navMenuItems>

Cannot pass props to component through connect()

I am using React / Redux with TypeScript transpilation. I want my navigation menu to read from state and to maintain its own mini-state.
NavMenu.tsx:
import * as React from 'react';
import { NavLink, Link, RouteComponentProps } from 'react-router-dom';
import { connect } from 'react-redux';
import { ApplicationState } from '../store';
import * as NavigationStore from '../store/Navigation';
type NavigationProps =
NavigationStore.NavigationState
& typeof NavigationStore.actionCreators;
class NavMenu extends React.Component<NavigationProps, {}> {
public render() {
return (
<nav className='main-nav'>
<ul className={`nav-standard`}>
<li>
<NavLink exact to={'/'} activeClassName='active'>
Home
</NavLink>
</li>
<li>
<NavLink to={'/learn'} activeClassName='active'>
Learn
</NavLink>
</li>
<li>
<NavLink to={'/blog'} activeClassName='active'>
Blog
</NavLink>
</li>
</ul>
<div className='nav-small'>
<button type='button' className='navbar-toggle' onClick={() => { this.props.toggle() } }>
<span className='screen-reader-content'>Toggle Navigation</span>
<i className='fa fa-bars'></i>
</button>
</div>
</nav>
);
}
}
export default connect(
(state: ApplicationState) => state.navigation,
NavigationStore.actionCreators
)(NavMenu) as typeof NavMenu;
Here is how I am trying to render the navbar, Layout.tsx:
import * as React from 'react';
import NavMenu from './NavMenu';
export class Layout extends React.Component<{}, {}> {
public render() {
return <div>
<NavMenu />
{ this.props.children }
</div>;
}
}
I'm getting a typescript transpilation error:
TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<NavMenu> & Readonly<{ children?: ReactNode; }> & R...'.
Type '{}' is not assignable to type 'Readonly<NavigationProps>'.
Property 'expanded' is missing in type '{}'.
Isn't this the purpose of the connect() function? To automatically map state and actions to a component? This is normally the error I get when not passing props down to a component (without using connect()).
EDIT
It does work when I exhaustively pass down all the properties expected for a NavigationProps type:
import * as React from 'react';
import NavMenu from './NavMenu';
export class Layout extends React.Component<{}, {}> {
public render() {
return <div>
<NavMenu expanded={false} expand={Navigation.actionCreators.expand} constrict={Navigation.actionCreators.constrict} toggle={Navigation.actionCreators.toggle} />
{ this.props.children }
</div>;
}
}
Navigation.ts for posterity (new import):
import { Action, Reducer } from 'redux';
export interface NavigationState {
expanded: boolean;
};
interface ExpandNavigationAction { type: 'EXPAND_NAVIGATION' }
interface ConstrictNavigationAction { type: 'CONSTRICT_NAVIGATION' }
interface ToggleNavigationAction { type: 'TOGGLE_NAVIGATION' }
type KnownAction = ExpandNavigationAction
| ConstrictNavigationAction
| ToggleNavigationAction;
export const actionCreators = {
expand: () => <ExpandNavigationAction>{ type: 'EXPAND_NAVIGATION' },
constrict: () => <ConstrictNavigationAction>{ type: 'CONSTRICT_NAVIGATION'
},
toggle: () => <ToggleNavigationAction>{ type: 'TOGGLE_NAVIGATION' }
};
export const reducer: Reducer<NavigationState> = (state: NavigationState,
action: KnownAction) => {
switch (action.type) {
case 'EXPAND_NAVIGATION':
return { expanded: true };
case 'CONSTRICT_NAVIGATION':
return { expanded: false };
case 'TOGGLE_NAVIGATION':
return { expanded: !state.expanded };
default:
const exhaustiveCheck: never = action;
}
return state || { expanded: false };
}
Even though this transpiles successfully, my goal when doing this was to avoid writing out such verbose markup. I was under the impression the whole point of the connect() method was to simply and easily pass the correct properties from state down to the child component via mapper methods.
Don't cast the result of connect() to typeof NavMenu. When you do that you're telling TS that the component expects a NavigationProps object to be passed in as a property. So it makes sense that you get an error when you don't pass in any properties.
The wrapped component created by connect() has no required properties.

Resources