Using propTypes to validate props gives the following error:
TypeError: Cannot read property 'string' of undefined.
TypeError: Cannot read property 'func' of undefined.
The code in question is at the bottom of the snippet:
import React from 'react';
import ProjectItem from './ProjectItem';
class Projects extends React.Component {
deleteProject(title) {
this.props.onDelete(title);
}
render() {
let projectItems;
if (this.props.project) {
projectItems = this.props.project.map(project => {
return (
<ProjectItem key={project.title} project={project} onDelete={this.deleteProject.bind(this)} />
)
});
}
return (
<div className="Projects">
{projectItems}
</div>
);
}
}
Projects.propTypes = {
projects: React.PropTypes.string,
onDelete: React.PropTypes.func
}
You need to install the prop-types package and then add the import statement
import PropTypes from prop-types;
at the top of your class.
The PropTypes have been moved from React to their own package prop-types.
EDIT: As mentioned in the comments, this is only applicable for React version 15.5 and above.
As palsrealm mentioned, you need to add the prop-types package, and then remove React before Proptypes. The following should work:
Projects.propTypes = {
projects: PropTypes.string,
onDelete: PropTypes.func
}
Related
I am not using React.
I am using Stenciljs.
I have the following .tsx file:
export class MyComponent {
#Prop() message: string;
render() {
return (<div>{this.message}</div>);
}
}
I want to do this instead:
import myTemplate from '../my-template.??';
export class MyComponent {
#Prop() message: string;
render() {
return (myTemplate);
}
}
with ../my-template.?? containing:
<div>{this.message}</div>
Is it possible and how ? Thanks in advance for any help :)
Yes, you can absolutely do this, there are just a couple of things you need to tidy up:
Main file
import { Template } from '../template'; // No need for file extension but we're using a named export so we need the curly braces around 'Template'
export class MyComponent {
#Prop() message: string;
render() {
return ( // You don't technically need the parentheses here as you're just returning one thing
<Template /> // When outputting an imported component, it goes in angle brackets and the backslash closes it like an HTML element
)
}
}
Template
import React from 'react'; // template needs React
export const Template = () => { // defining the export in this way is known as a named export
return (
<p>A message here</p>
)
}
Okay, so that's going to get you a message output which is from your template. However, you were asking about passing a message to that template for it to output. That's totally easy as well - you just need to get some props in there. Here is the modified version of the above:
Main file
import { Template } from '../template';
export class MyComponent {
#Prop() message: string;
render() {
return (
<Template messageToOutput={message} /> // The first argument is the name of the prop, the second is the variable you defined above
)
}
}
Template
import React from 'react';
export const Template = (props) => { // props are received here
return (
<p>{props.messageToOutput}</p> // props are used here
)
}
That's how you pass data around in React - hope that helps!
Code works fine, but I can't figure out how to remove this error in VSCode.
Thanks for help.
import * as React from 'react';
interface State {
text: string;
}
export default class Example extends React.Component<State> {
state: State = {
text: 'SOME TEXT'
}
private handleChange = () => {
this.setState({text: 'New Text'}); //error: property setState does not exist on type Example
}
public render(){
return(
<div>
<h2 onClick={this.handleChange}>{this.state.text}</h2>
</div>
)
}
}
First off, make sure you have the react type definitions installed:
npm install #types/react #types/react-dom
Secondly, the generic for state goes second, not first. The first one is for props.
export default class Example extends React.Component<{}, State> {
Look at the React type definitions to verify this (go to definition on Component). <P, S> means props, then state.
class Component<P, S> {
I resolved the same issue in VSCode just by changing the version of typescript used
=> open command palette > "select typescript version" > "use workspace version"
React provides proptypes for type checking as the following code block demonstrates:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
But I can do the following as well for the 'name' proptype:
Greeting.propTypes = {
name: String
};
In the later case i don't need to include the 'prop-types' module. Which one is the recommended approach?
The first way is the recommended way.
When you do
Greeting.propTypes = {
name: String
};
you are defining a javascript string field inside your proptypes object. Also, you will not be able to make the prop a required prop by using the above.
By using this
Greeting.propTypes = {
name: Proptypes.string.isRequired
};
you can make the proptype required and show a console warning if it is not supplied.
I'm sure there's something stupid that I'm missing, but I can't get my TypeScript compiler to compile a fairly simply React component. I'm using a .tsx file extension for my file which TypeScript should be able to handle via my webpack config. I get the following error: ERROR in ./src/App.tsx
(36,16): error TS2339: Property 'todos' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<ToDosList> & Readonly<{ children?: ReactNode; }> &...'.
Below is my code. I've tried both implicitly setting the state for the component (meaning without setting state: App.State) and explicitly giving state a type of App.State, but neither seem to work.
import * as React from 'react';
import ToDosList from './components/todos_list';
const todos = [
{
task: 'Make React tutorial',
is_completed: false
},
{
task: 'Eat Dinner',
is_completed: true
}
];
namespace App {
export interface Props {
}
export interface State {
todos: any
}
}
export default class App extends React.Component<App.Props, App.State> {
constructor(props) {
super(props);
this.state = { todos: todos };
}
render() {
return (
<div>
<h1>React ToDos App</h1>
<ToDosList todos={this.state.todos} />
</div>
);
}
}
Going through the TodoMVC example of Redux I have found this unusual example of class inheritance. The class Header is probably extending React.Component as per usual (as should all React components, right?), but it is not explicitly stated in the code. What am I missing? How does this code work?
import React, { PropTypes } from 'react';
import TodoTextInput from './TodoTextInput';
export default class Header {
static propTypes = {
addTodo: PropTypes.func.isRequired
};
handleSave(text) {
if (text.length !== 0) {
this.props.addTodo(text);
}
}
render() {
return (
<header className='header'>
<h1>todos</h1>
<TodoTextInput newTodo={true}
onSave={::this.handleSave}
placeholder='What needs to be done?' />
</header>
);
}
}
If you don't need the methods defined by ReactComponent (setState() and forceUpdate()) you don't have to inherit from it.
As such, it isn't an example of class inheritance or magic because neither is happening here :)