React gives us a mechanism called PropTypes to ensure that the property values passed into components are of the correct type. By ensuring the correct data is passed to our components, we can avoid potential bugs and more confidently share components with a team or as open source libraries.
[00:00] This todo form component represents a form that we can use to create new todo items. In order for it to function properly, it receives a prop that is used to set the value of the input. It also receives a function as a prop and that's how we pass event information, input change events in this case to its parent component.
[00:19] If another member of our team wanted to use this component in another part of the application we'd like to be able to ensure they are passing in the correct props. Luckily, React has a mechanism for validating our component input called prop types. The first step in defining prop types for a component is to reference that component and call its prop types property.
[00:41] That's going to be equal to an object. This object will have keys that match our property name. I'll start with current todo. We want to specify the current todo should be a string. We'll do that by calling react.proptypes.string. It's important to note when we're referencing prop types off of React to pick the type for our property we want to make sure we use the prop types here with a capital P.
[01:06] When we're defining the prop types object for our component we define that property with a lower case p. Now that that's done I'm going to go into the browser and open up the DevTools. I'm going to jump into App.js and I'm just going to temporarily take this.state.currenttodo out of here. I'm going to define that as a number. I'm going to save that.
[01:31] We'll see when the browser refreshes that the value shows up because it will turn anything into a string. Down here we have this warning, "Failed prop type. Invalid prop current todo of type number supply to todo form expected string." We got a very helpful message that we can go back. We can say that needs to be a string. I'll go ahead and put that value back.
[01:53] I'll save that and when it reloads again that warning is gone. Now I can go back to todo form and I'm going to specify that I also want a handle input change property. That should be of type [inaudible] .proptypes.func. I'll save that. That's going to ensure that whatever is passed into handle input change is a function.
[02:23] I'm preventing properties from being passed that are of the wrong data type. At this point both of these properties are basically optional for this component. If you absolutely have to have those properties and in this case we do for this component to do anything want to make sure those things are passed in and not left out.
[02:43] I can just come in here and I can take on an is required to any of the properties that I define in prop types. That will ensure that the property has to be passed in to avoid that warning in the console. If I jump back over to the browser, open up the console. I'm just going to again temporarily update App.js. We'll say we're just not going to pass current todo at all.
[03:10] When the browser reloads, we'll see the current todo is marked as required but its value is undefined. I can just put that back, save it. Now my warning goes away.
[03:24] Let's define prop types for a couple more components. We'll start with our todo list component. We'll see here that this basically takes in a single prop called todos.
[03:34] To add that prop type definition I'm just going to reference todolist.proptypes set that equal to an object. I want to specify todos is going to be of type react.Proptypes.array and I need to have that for this to work, so that is required. We'll save that. When the browser reloads we don't get any errors, so all of our props are being passed in properly.
[04:05] We can go to todoitem.js. We'll drop down to the bottom and we'll say todoitem.proptypes so that's equal an object. Todo item receives an entire todo object, so that's going to have three properties name, which is going to be a string. We'll save it past required. We're also going to have is complete. That's going to be a Boolean value, so we'll specify that with bool.
[04:42] We're not going to make this required because if it's undefined it will default to falsey and that's fine. We're not using it in the component yet, but we are going to need the ID from the todo, so we'll also accept an ID of type number. We'll say that is required as well.
[05:05] Upon save, our browser will reload. We don't have any warnings, so everything is adhering to the prop types we just defined.
npm run start
bam@Johns-MacBook-Pro:~/.npm/_logs
0 info it worked if it ends with ok
1 verbose cli [ '/Users/bam/.nvm/versions/node/v7.0.0/bin/node',
1 verbose cli '/Users/bam/.nvm/versions/node/v7.0.0/bin/npm',
1 verbose cli 'run',
1 verbose cli 'start' ]
2 info using npm@5.0.4
3 info using node@v7.0.0
4 verbose run-script [ 'prestart', 'start', 'poststart' ]
5 info lifecycle todo_react@0.1.0~prestart: todo_react@0.1.0
6 silly lifecycle todo_react@0.1.0~prestart: no script for prestart, continuing
7 info lifecycle todo_react@0.1.0~start: todo_react@0.1.0
8 verbose lifecycle todo_react@0.1.0~start: unsafe-perm in lifecycle true
9 verbose lifecycle todo_react@0.1.0~start: PATH: /Users/bam/.nvm/versions/node/v7.0.0/lib/node_modules/npm/bin/node-gyp-bin:/Users/bam/Documents/practice_work/todo_react/node_modules/.bin:/Users/bam/.rbenv/shims:/Users/bam/.rbenv/bin:/Users/bam/.nvm/versions/node/v7.0.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/share/dotnet:/usr/local/git/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/bam/.fzf/bin
10 verbose lifecycle todo_react@0.1.0~start: CWD: /Users/bam/Documents/practice_work/todo_react
11 silly lifecycle todo_react@0.1.0~start: Args: [ '-c', 'react-scripts start' ]
12 info lifecycle todo_react@0.1.0~start: Failed to exec start script
13 verbose stack Error: todo_react@0.1.0 start: react-scripts start
13 verbose stack spawn ENOENT
13 verbose stack at ChildProcess.<anonymous> (/Users/bam/.nvm/versions/node/v7.0.0/lib/node_modules/npm/lib/utils/spawn.js:33:16)
13 verbose stack at emitTwo (events.js:106:13)
13 verbose stack at ChildProcess.emit (events.js:191:7)
13 verbose stack at maybeClose (internal/child_process.js:877:16)
13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5)
14 verbose pkgid todo_react@0.1.0
15 verbose cwd /Users/bam/Documents/practice_work/todo_react
16 verbose Darwin 16.6.0
17 verbose argv "/Users/bam/.nvm/versions/node/v7.0.0/bin/node" "/Users/bam/.nvm/versions/node/v7.0.0/bin/npm" "run" "start"
18 verbose node v7.0.0
19 verbose npm v5.0.4
20 error file sh
21 error code ELIFECYCLE
22 error errno ENOENT
23 error syscall spawn
24 error todo_react@0.1.0 start: react-scripts start
24 error spawn ENOENT
25 error Failed at the todo_react@0.1.0 start script.
25 error This is probably not a problem with npm. There is likely additional logging output above.
26 verbose exit [ 1, true ]
I just had to install react-scripts...
If anyone is interested, this is how I dealt with PropTypes (I did use prop-types package), but I also kept the stateless functional components. In addition, I am NOT using create-react-app: https://github.com/interglobalmedia/react-todo-app/commit/ab3053135cd490bb745c3c346ffd1df850369d73?diff=unified
Why is PropTypes depreacted? Is it cause of performance issues or what?
If you're using React 15.5.0 or higher, then you have to to import PropTypes
first. Like this:
import React from 'react'
import PropTypes from 'prop-types'
export const TodoForm = (props) => (
{/*code goes here.. */}
)
TodoForm.propTypes = {
currentTodo: PropTypes.string
}
Coming from years of Angular.... and.. honestly I am blown away by React. React enforces best practices such as presentational components naturally, and the code is just so much easier to work with. Angular's @input() / @output bindings are a huge mess compared to stateless functional components.
Just to follow up, this shows up as a javascript error and could cause confusion and will eventually not work.