41.B站 react三大属性2:props - yiqunkeke/react-jianshu-shangguigu-zty GitHub Wiki
state是组件内部的,类似于自家事。
需求:从组件外部往组件内部带东西。
// 创建组件
class Person extends React.Component {
render() {
console.log(this)
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
// <Person name="tom"/> React做了什么?
// React 在帮你new 这个 Person实例的时候,就自动地把你所写的 name作为key,把你写的tom作为value,把这一组key-value帮你收集好了,放在了this.props对象上。
// 也就是说放在了组件实例对象的props属性上。
// 创建组件
class Person extends React.Component {
render() {
console.log(this)
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
// 渲染组件到页面
const p = {name: '老刘', age: 18, sex: '女'}
// ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
ReactDOM.render(<Person {...p}/>, document.getElementById('test')) // 上面写法的语法糖
展开运算符是不能够展开对象的。
let arr1 = [1,3,5,7,9]
let arr2 = [2,4,6,8,10]
// 1.展开一个数组
console.log(...arr1) // 1 3 5 7 9
// 2.连接两个数组
let arr3 = [...arr1, ...arr2]
console.log(arr3) // [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
// 3.函数传参
function sum(...numbers) {
console.log(numbers) // [1, 2]
// 计算一个数组中所有数值的和
// reduce方法有返回值,返回整个数组的和
return numbers.reduce((preValue, currentValue) => {
return preValue + currentValue
})
}
sum(1, 2)
// 前端人员的职责:在合适的时候发出合适的请求,把合适的数据展示到合适的位置。
// 4.不能把展开运算符直接应用到对象上。<==> 展开运算符不能展开对象。
let person = {name: 'tom', age: 18}
console.log(...person) // 报错:展开运算符不能展开对象
// 5.对象引用关系的传递
let p1 = {name: 'tom', age: 18}
let p2 = p1
p1.name = 'jerry'
console.log(p2.name) // jerry
// 6.复制对象
let p3 = {name: 'tom', age: 18}
// 字面量形式---复制对象
let p4 = {...p3} // ...不可以展开对象。但是如果...外面包裹了{},则可以复制一个对象。
p3.name = 'jerry'
console.log(p4.name)
// 7. 为什么这里可以展开一个对象? react + babel 结合之后,允许你使用展开运算符展开一个对象了。
ReactDOM.render(<Person {...p}/>, document.getElementById('test'))
// 8. 复制对象的同时修改它的属性---合并
let p5 = {...p3, name: 'jack'}
console.log(p5)
React 和 babel 结合使用,允许我们使用展开运算符展开对象。且仅仅适用于标签属性的传递。原生写法是不能直接展开一个对象。
是不是要对组件实例对象props属性进行限制。也就是 对 this.props进行限制。
组件实例对象是由谁new出来的? ----是由你所定义的Person组件
你每写一次<Person/>
标签,react 都能帮你new出来一个Person实例。在组件实例对象身上的props里面就囊括着你所有传进去的东西。
所以跟缔造实例的人----Person组件,去对话是最管用的。跟它去约定规则。
ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
ReactDOM.render(<Person name="jerry" age="19" sex="女"/>, document.getElementById('test2'))
// 每写一次<Person/>标签,react都能帮你new一个实例。
// 实例都是由Person类new出来的。所以约定规则定义在Person类身上。
// 伪代码
// Person.属性规则 = {
// name: '必传,字符串'
// }
// 这里类身上的 propTypes 属性不允许改,react底层会找这个属性。react每一次在帮你new实例对象的时候,都会去问一下Person身上有没有propTypes属性。如果没有,react就不会帮你限制了,如果有,react就会要求Person把具体规则给它。
// 这个 propTypes 是react的一个规矩:你只要敢给类加 propTypes属性,我就会认为你在给 props属性加规则 。
Person.propTypes = {
// 这里的React.PropTypes是内置规则
name: React.PropTypes.string
}
// 这样定义后,传递进来的name属性的值就只能是字符串类型
// 在 react 15.xxxx版本上, react一直在维护 React.PropTypes。但是在react 16版本之后 React.PropTypes形式就被弃用了。
// 因为react发现,如果一直在这个最为核心的 React身上维护PropTypes这个属性,就会导致React这个核心对象很大,而且有些时候人们也不一定非要进行限制。所以感觉 PropTypes直接挂在 React身上不太合适。因为有些时候PropTypes并不需要。
// 所以在 react 16之后,PropTypes属性已经不从 React身上取了。而是从 prop-types 库中取。
// 引入 react.development.js----全局多了一个React对象
// 引入 react-dom.development.js ----全局多了一个ReactDOM对象
// 引入 prop-types.js------全局多了一个PropTypes对象
Person.propTypes = {
name: PropTypes.string
}
Person.propTypes = {
name: PropTypes.isRequired // name属性必传
}
// 给类加上 defaultProps 属性。 对传递进来的标签属性或者叫 props 设置默认值
Person.defaultProps = {
sex: '不男不女' // 设置sex默认值,当不传递sex时,会显示默认值
}
// 创建组件
class Person extends React.Component {
render() {
const {name, age, sex} = this.props // 读取props
// props是只读的
// this.props.name = 'jack' // 此行代码会报错,因为props是只读的。所以通常我们只是读取和使用props属性
// 使用 props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
分析下面代码:
// 创建组件
class Person extends React.Component {
render() {
const {name, age, sex} = this.props // 读取props
// props是只读的
// this.props.name = 'jack' // 此行代码会报错,因为props是只读的。所以通常我们只是读取和使用props属性
// 使用 props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
}
// 对标签属性进行类型、必要性的限制
Person.propTypes = {
name: PropTypes.string
}
// 对标签属性指定默认值
Person.defaultProps = {
sex: '不男不女'
}
// 上面两部分,Person.propTypes和 Person.defaultProps 都是给类自身加的属性。可以通过static写在类的内部去。
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
所以,简写之后的代码是:
// 创建组件
class Person extends React.Component {
// 对标签属性进行类型、必要性的限制
static propTypes = {
name: PropTypes.string
}
// 对标签属性指定默认值
static defaultProps = {
sex: '不男不女'
}
// 只要能够保证类自身有 propTypes 属性和 defaultProps 属性,react就能够帮你做限制。至于是怎么添加这两个属性的,react不管。所以我们把限制写在类的内部,代码更加清晰。跟组件相关的东西,都在类里面。
render() {
const {name, age, sex} = this.props // 读取props
// props是只读的
// this.props.name = 'jack' // 此行代码会报错,因为props是只读的。所以通常我们只是读取和使用props属性
// 使用 props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18" sex="男"/>, document.getElementById('test'))
// 创建组件
class Person extends React.Component {
// 构造器是否接收 props,是否传递给super,取决于:是否希望在构造器中通过this访问 props
constructor(props) {
console.log(props) // 这里props 与 组件实例对象上的 this.props 一样
// 为什么要把props传给super? ---
// 在为React.Component子类实现构造函数时,应在其他语句之前调用 super(props)。否则, this.props在构造函数中可能会出现未定义的bug。
// super(props)
super()
console.log(this.props) // 输出实例自身的props--如果constructor中不接收props,super中也不传props。或者constructor中接收了props,但没有传递给super,那么,这里实例自身的this.props就都是undefined.
}
// 类中的构造器到底有什么作用?
// 1. 给state初始化属性 --> this.state = { ... }
// 2. 为事件处理绑定实例 --> this.demo = this.demo.bind(this)
// 但这个都可以通过 直接在类中添加state属性 和 赋值语句+箭头函数 来解决。所以构造器是可以不写的。
static propTypes = {
name: PropTypes.string
}
static defaultProps = {
sex: '不男不女'
}
render() {
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18"/>, document.getElementById('test'))
如果在构造器中,不接收props,super中也不传递props,则无法在构造器中通过实例使用props。即无法在构造器中使用 this.props。
总结:
构造器是否接收 props,是否传递给super,取决于:是否希望在构造器中通过this访问 props。
// 创建组件
function Person(props) {
console.log(props)
const {name, sex, age} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18" sex="女"/>, document.getElementById('test'))
函数式组件只可以用 props,不能用 state 和 refs。
只能在组件外部使用 propTypes
和 defaultProps
属性对传进来的props做限制
// 创建组件
function Person(props) {
console.log(props)
const {name, sex, age} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}<li/>
</ul>
)
}
// 函数式组件对props做限制,只能通过在组件外部给组件自身添加propTypes和defaultProps属性的方式。
// 不能写在组件内部。类式组件可以使用static将propTypes和defaultProps属性定义在组件内部。
Person.propTypes = {
name: PropTypes.string
}
Person.defaultProps = {
sex: '不男不女'
}
// 渲染组件到页面
ReactDOM.render(<Person name="tom" age="18"/>, document.getElementById('test'))