41.B站 react三大属性2:props - yiqunkeke/react-jianshu-shangguigu-zty GitHub Wiki

组件实例三大核心属性2:props

state是组件内部的,类似于自家事。

需求:从组件外部往组件内部带东西。

1. 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>
        )
    }
}

// 渲染组件到页面
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属性上。

2.批量传递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')) // 上面写法的语法糖

3. 关于展开运算符

展开运算符是不能够展开对象的。

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 结合使用,允许我们使用展开运算符展开对象。且仅仅适用于标签属性的传递。原生写法是不能直接展开一个对象。

4. 对组件传递的标签属性的“类型”进行限制

是不是要对组件实例对象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  
}

5. 对组件传递的标签属性的“必要性”进行限制

Person.propTypes = {
    name: PropTypes.isRequired // name属性必传  
}

6. 给组件传递的标签属性设置“默认值”

// 给类加上 defaultProps 属性。 对传递进来的标签属性或者叫 props 设置默认值 
Person.defaultProps = {
    sex: '不男不女' // 设置sex默认值,当不传递sex时,会显示默认值
}

7. props是只读的

// 创建组件
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'))

8. props简写方式

分析下面代码:

// 创建组件
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'))

9. 构造器与props

// 创建组件
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

10. 函数式组件使用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

11. 函数式组件对props做限制

只能在组件外部使用 propTypesdefaultProps属性对传进来的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'))
⚠️ **GitHub.com Fallback** ⚠️