承接上文

<body>
    <div id="test1"></div>
    <div id="test2"></div>
    <!-- 引入核心库 -->
    <script src="../js/react.development.js"></script>
    <!-- 扩展库 -->
    <script src="../js/react-dom.development.js"></script>
    <!-- 转换jsx转为js -->
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
      class Person extends React.Component {
        render() {
          console.log("this", this);
          const { name, sex, age } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age + 1}</li>
            </ul>
          );
        }
      }
      const p = { name: "tom", sex: "男", age: 1 };
      ReactDOM.render(<Person name="jerry" age="19" sex="男" />,document.getElementById("test1"));
      ReactDOM.render(<Person {...p} />, document.getElementById("test2"));
    </script>
  </body>

produces指定_默认值

现在实现一个小需求,展示的年龄比实际年龄大1岁。
比较简单,也就是对age+1

<script type="text/babel">
      class Person extends React.Component {
        render() {
          const { name, sex, age } = this.props;
          return (
            <ul>
              <li>姓名:{name}</li>
              <li>性别:{sex}</li>
              <li>年龄:{age + 1}</li>
            </ul>
          );
        }
      }
      const p = { name: "tom", sex: "男", age: 18 };
      ReactDOM.render(<Person name="jerry" age="19" sex="男" />,document.getElementById("test1"));
      ReactDOM.render(<Person {...p} />, document.getElementById("test2"));
    </script>

打印后会发现

produces指定_默认值_02


jerry的年龄是191,tom则是正常的19。

这是因为tom的age是Number类型,jerry的age是String类型。

produces指定_默认值_03


这时,我们把jerry的age改成Number类型时,语法发生报错。

produces指定_数据类型_04


当我们想传递Number类型的值时,要写成{19},这是因为在js事件中才能提数据类型,才涉及到数据类型的判断

const p = { name: "tom", sex: "男", age: 18 };
ReactDOM.render(<Person name="jerry" age={19} sex="男"/>,document.getElementById("test1"));
ReactDOM.render(<Person {...p} />, document.getElementById("test2"));

这时,我们思考一个问题,{19}这种写法,是写在我们自己定义的Person组件中,
我们清晰的知道,需求上是对年龄加1,所以才这样写。但是,对于他人遇见类似需求时,并使用我们写的组件进行开发,是并不知道我们是否正确书写Number类型的传值{19},所以是有可能写下String类型的“19”,导致错误数据。
所以,我们需要对Person组件传递的标签属性进行类型上的限制。 在以上基础上再拓展小需求,1.当性别不传递时,默认显示男。2.姓名是必传。
稍微整理一下:

  1. 对props传值进行类型限制。
  2. 某个属性的默认值
  3. 必填项

如何限制?也就是对组件实例对象里的props进行限制,也就是传递的值进行限制

produces指定_produces指定_05


组件实例对象是由谁new出来?是我们定义的person组件,每写一个person组件,react都会帮我们new一个组件实例,在组件实例props中就包括了所有传递的内容。

我们先来一段伪代码,设想自己是props的设计者,该如何去限制

Person.属性规则 = {
  name:'必传,字符串'
};
const p = { name: "tom", sex: "男", age: 18 };

而在react要求中,是往react实例person自身添加一个属性,属性名叫做propTypes,prop有属性的意思,type有种类的意思。当给person加上propTypes时,并添加具体规则,react就能帮你限制。

Person.propTypes = {
  name:React.PropTypes
};

别写错了,两个属性非常像,PropTypes属于React内置属性

Person.propTypes = {
  name:React.PropTypes.string
};

React.PropTypes.string就是给name添加了属性限制(规则),但是我们打开控制台时,发现报错信息Uncaught TypeError: Cannot read properties of undefined (reading ‘string’),简单的理解就是不能读取sting在undefined身上,所以是.string,.的左侧出了问题。

produces指定_produces指定_06


也就是PropTypes是undefined ,这里要说明一下,在React15.xxx版本的时候,React一直在维护这个属性,之后就弃用了这个属性(由于是绑定在React上的,且不是必用属性,导致React冗余)。

需要一个库支持

produces指定_produces指定_07

Person.propTypes = {
  name: PropTypes.string,
};
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(
  <Person name="tom" sex="女" age={18} />,
  document.getElementById("test2")
);

页面正常显示

produces指定_数据类型_08


现在我们将tom的名字改为{10}实验一下

ReactDOM.render(<Person name={10} sex="女" age={18} />,document.getElementById("test2"));

打开控制台

produces指定_默认值_09


报错信息如下:

react.development.js:2726 Warning: Failed prop type: Invalid prop name of type number supplied to Person, expected string.

意思是,我希望是name一个string,但是得到一个number,这种控制台的明显报错,并可提示开发者正确传递属性,也就完成第一个小需求:对props传值进行类型限制。

接下来看第三个,必填项,PropTypes提供一个 isRequired属性,来限制props的默认值,示例如下

Person.propTypes = {
  name: PropTypes.string.isRequired,
};

控制台打印如下

produces指定_报错信息_10


Warning: Failed prop type: The prop name is marked as required in Person, but its value is undefined.

意思是:名字被标记为必填项,但是传递了一个undefined。

解决了第三个小需求,必填项,接下来看剩下的小需求,某个属性的默认值,这涉及到另一个属性,defaultProps,挂载在Person实例身上。

Person.propTypes = {
  name: PropTypes.string.isRequired,
};
Person.defaultProps = {
  sex:'女'
}
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name='tom' age={18} />,document.getElementById("test2"));

produces指定_默认值_11


再来看一个问题,年龄是Number类型,且不是必填的,这时我去掉age={18}

Person.propTypes = {
  name: PropTypes.string.isRequired,
  sex:PropTypes.string,
  age:PropTypes.number
};
Person.defaultProps = {
  sex:'女'
}
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name='tom' age={18} />,document.getElementById("test2"));

你会发现控制台报

produces指定_数据类型_12


这是因为

produces指定_默认值_13

所以给一个默认值就好了,加点注释

// 指定属性类型及设置必填项
Person.propTypes = {
  name: PropTypes.string.isRequired,
  sex: PropTypes.string,
  age: PropTypes.number,
};
// 设置默认属性
Person.defaultProps = {
  sex: "女",
  age: 18,
};

另外有一个注意事项,我们可以加一点内容,比如说加一个说话的方法,并且做一个限制,想到的是function

Person.propTypes = {
  name: PropTypes.string.isRequired,
  sex: PropTypes.string,
  age: PropTypes.number,
  speak: PropTypes.function
};
// 设置默认属性
Person.defaultProps = {
  sex: "女",
  age: 18,
};
const p = { name: "jeery", sex: "男", age: 17 };
function speak() {
  console.log("我说话了");
}
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name="tom" speak={speak} />, document.getElementById("test2"));

打开控制台

produces指定_报错信息_14


Failed prop type: Person: prop type speak is invalid; it must be a function, usually from the prop-types package, but received undefined.

这里的意思是,speak必须是个函数,但是是个undefined,这是因为funciton写的不对,如下

Person.propTypes = {
  name: PropTypes.string.isRequired,
  sex: PropTypes.string,
  age: PropTypes.number,
  speak: PropTypes.function
};

string,number没有首字母大写,是因为避免与内置String冲突,而function是定义函数的关键字,正确的写法是func