Reputation: 75
Some time ago I tried to make my first steps in React. Now I'm trying to create simple ToDo list app. One of my colleagues told me that it will be nice to use PropTypes with shape and arrayOf. I have one component which pass data to another and here is my issue(List.js and ListItem.js). I'm not sure when, where and how to use propTypes with shape and arrayOf. Which approach is right? Define PropTypes in parent component or in child component? Maybe there is a better idea? Please find my code below, it will be nice if you can clarify me how to use PropTypes. I tried to search something in Web, but I still don't get it.
Main App.js file:
import React from "react";
import "./styles/App.scss";
import List from "./components/List/List";
import AppHeader from "./components/AppHeader/AppHeader";
function App() {
return (
<div className="App">
<AppHeader content="TODO List"></AppHeader>
<List></List>
</div>
);
}
export default App;
AppHeader.js file:
import React from "react";
import "./AppHeader.scss";
export default function AppHeader(props) {
return (
<div className="header">
<h1 className="header-headline">{props.content}</h1>
</div>
);
}
List.js file:
import React from "react";
import "./List.scss";
import ListItem from "../ListItem/ListItem";
import _ from "lodash";
const initialList = [
{ id: "a", name: "Water plants", status: "done" },
{ id: "b", name: "Buy something to eat", status: "in-progress" },
{ id: "c", name: "Book flight", status: "in-preparation" }
];
const inputId = _.uniqueId("form-input-");
// function component
const List = () => {
const [value, setValue] = React.useState(""); // Hook
const [list, setList] = React.useState(initialList); // Hook
const handleChange = event => {
setValue(event.target.value);
};
// add element to the list
const handleSubmit = event => {
// prevent to add empty list elements
if (value) {
setList(
list.concat({ id: Date.now(), name: value, status: "in-preparation" })
);
}
// clear input value after added new element to the list
setValue("");
event.preventDefault();
};
// remove current element from the list
const removeListItem = id => {
setList(list.filter(item => item.id !== id));
};
// adding status to current element of the list
const setListItemStatus = (id, status) => {
setList(
list.map(item => (item.id === id ? { ...item, status: status } : item))
);
};
return (
<div className="to-do-list-wrapper">
<form className="to-do-form" onSubmit={handleSubmit}>
<label htmlFor={inputId} className="to-do-form-label">
Type item name:
</label>
<input
type="text"
value={value}
onChange={handleChange}
className="to-do-form-input"
id={inputId}
/>
<button type="submit" className="button to-do-form-button">
Add Item
</button>
</form>
<ul className="to-do-list">
{list.map(item => (
<ListItem
name={item.name}
status={item.status}
key={item.id}
id={item.id}
setListItemStatus={setListItemStatus}
removeListItem={removeListItem}
></ListItem>
))}
</ul>
</div>
);
};
export default List;
And ListItem.js file:
import React from "react";
import PropTypes from "prop-types";
import "./ListItem.scss";
const ListItem = props => {
return (
<li className={"list-item " + props.status} key={props.id}>
<span className="list-item-icon"></span>
<div className="list-item-content-wrapper">
<span className="list-item-text">{props.name}</span>
<div className="list-item-button-wrapper">
<button
type="button"
onClick={() => props.setListItemStatus(props.id, "in-preparation")}
className="button list-item-button"
>
In preparation
</button>
<button
type="button"
onClick={() => props.setListItemStatus(props.id, "in-progress")}
className="button list-item-button"
>
In progress
</button>
<button
type="button"
onClick={() => props.setListItemStatus(props.id, "done")}
className="button list-item-button"
>
Done
</button>
<button
type="button"
onClick={() => props.removeListItem(props.id)}
className="button list-item-button"
>
Remove
</button>
</div>
</div>
</li>
);
};
ListItem.propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
name: PropTypes.string,
status: PropTypes.string,
removeListItem: PropTypes.func,
setListItemStatus: PropTypes.func
};
export default ListItem;
Upvotes: 0
Views: 494
Reputation:
Props are per component.
The purpose of prop types is to let you make some type checking on a component's props.
It seems like you did it correctly in the ListItem component.
Basically, you just list all of the component's props and what type they should be.
Like you did here:
ListItem.propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
name: PropTypes.string,
status: PropTypes.string,
removeListItem: PropTypes.func,
setListItemStatus: PropTypes.func
};
Upvotes: 2
Reputation: 42526
I am not exactly sure where will the propTypes shape
and arrayOf
be used, but generally, PropTypes are useful when you are trying to render a child component within a parent component, and you want to carry out TypeChecking
on the props of the relative child component.
In your scenario, arrayOf
and shape
can be used in one of the props within your component whereby the prop is an array of a certain type (arrayOf
), and an object of a certain type(shape
, or exact
).
Upvotes: 1