yaofly2012 / note

Personal blog
https://github.com/yaofly2012/note/issues
44 stars 5 forks source link

Reactjs-props #75

Open yaofly2012 opened 4 years ago

yaofly2012 commented 4 years ago

props

image Props and Data Flow in ReactJS

一、 props

  1. props是组件的输入参数,是父组件向子组件传递数据的唯一途径。
  2. props是只读的。

1.1 访问props

props是只读的。从React 0.14开始会把props对象进行冻结(Object.freeze),但不会递归的去冻结props的子属性。

this.props.a = [1,2,3]; // won't work

this.props.a.push(123); // will work.

this.props.a = {name: 'John Doe'}; // won't work

this.props.a.name = 'John Doe'; // will work

摘自React: Why are props not frozen?

为什么必须是只读的

React文档里这样说到:

React is pretty flexible but it has a single strict rule: All React components must act like pure functions with respect to their props.

组件具有stateprops,组件可以通过setState管理state,并且组件只能管理自己的state。组件是不可以管理自己的props,因为props是组件的输入,一般来自父组件的state,所以对子组件来说props是只读的,不可以修改props,如果要修改得由props数据来源的父组件修改。

为什么不递归的冻结props的子属性

  1. 递归遍历本身性能就差;
  2. 还是跟state有关,state的变化跟踪也只是针对state的子属性。

总结:

props作为组件的输入,所有的React组件必须像纯函数那样使用它们的输入(即props

1.2 指定默认值

约定静态属性defaultProps指定组件属性的默认值:

  1. 当没有属性或者传给组件的属性值为undefined时,则尝试从defaultProps里取默认值;
  2. 除了对挂载阶段的构造函数的props参数值应用默认值,更新阶段的componentWillReceiveProps方法的参数也会被尝试应用默认值。
  3. defaultProps只应用在属性的子属性上,不会递归处理。
class DisplyMsg extends React.Component{
    static defaultProps = {
        msg: 'this is a default msg',
        type: 'text'
    }
       // props = Object.assign({}, 父组件传的值, DisplyMsg.defaultProps )
    constructor(props) { 
        super(props);
        console.log(props)
    }
       // newProps= Object.assign({}, 父组件传的值, DisplyMsg.defaultProps )
    componentWillReceiveProps(newProps) {
        console.log(`componentWillReceiveProps`)
    }
    render() {
        return (
            <div>
                <pre>{ this.props.msg }</pre>
            </div>
        )
    }   
}
// 
<DisplyMsg msg=“hello”></DisplyMsg>

1.3 特殊的属性

有些属性是Reactjs内部处理的

明明写了,却没有收到

  1. ref
  2. key

明明没写,却收到了

  1. children

传给style属性的对象

React除了不建议props对象作为可修改对象外,还不建议把传给style属性的对象作为可修改对象。并且从React 16开始也传给style属性的对象冻结了(Object.freeze

if (propKey === STYLE) {
      if (__DEV__) {
        if (nextProp) {
          // Freeze the next style object so that we can assume it won't be
          // mutated. We have already warned for this in the past.
          Object.freeze(nextProp);
        }
      }

参考

  1. 知乎 React v16.3之后的组件生命周期函数
  2. React 16 中 Props 的只读性
  3. Are React v16 props frozen or sealed ?
  4. Why was mutating style deprecated?
  5. A Guide to Props in React
  6. Why props in React are read only?
yaofly2012 commented 3 years ago

深入理解props.children属性

props.children属性取值来源

  1. 显示的给组件添加children属性;
    
    import React from 'react';

class Index extends React.Component { render() { console.log(this.props.children); return (

{this.props.children}
) } }

export default function() { return ( <Index children={["b", "c"]}> ) }

这种情况下children的数据类型完全由开发者明确指定的。

2. React隐式的添加`children`属性,包含在开始和结束标签之间的 JSX 表达式内容将作为特定属性 props.children 传递给外层组件;
```jsx
import React from 'react';

class Index extends React.Component {
  render() {
    console.log(this.props.children);
    return (<div>{this.props.children}</div>)
  }
}

export default function() {
  return (
    <Index>
      Hello World
    </Index>
  )
}

这也是经常遇到的场景。

组件是React的核心。你可以像嵌套HTML标签一样嵌套使用这些组件,这使得编写JSX更加容易因为它类似于标记语言。

  1. 如果同时存在1和2情况,则优先2;
  2. 如果同时不存在1和2情况,则没有children属性。

    children属性类型

    记住4点:

  3. 嵌套在组件内的所有表达式的值或者组件(这里统称元素)都是children属性的取值;
  4. 如果有多个嵌套元素,则children属性为数组,数组的每个元素就是嵌套在组件内的组件或者表达式;
  5. 如果只有一个嵌套元素,则children属性值直接是该嵌套元素的值(所以children属性不一定是数组);
  6. children属性或者数组的元素(当children是数组时)本质上可以是任意类型的数据。但是并不是所有类型的数据都可以被正确渲染(看深入理解JSX)。
    
    import React from 'react';

class Index extends React.Component { render() { console.log(this.props.children); return (

{this.props.children}
) {/这里直接渲染children/} } }

export default function() { return (

{{a: 12}} {/*这里children是个对象*/}

) }

> Objects are not valid as a React child (found: object with keys {a}). If you meant to render a collection of children, use an array instead.

## 操作`children`属性 
>“children是一个不透明的数据结构”

虽然类型不定,但是属性的特性是固定的([Props are Read-Only](https://reactjs.org/docs/components-and-props.html)),无论是方式1还是方式2指定children属性值,React内部都会重新复制一份对应的值,但修改了特性值:
**children属性和属性值(数组时)都是只读的,可枚举的的,不可配置的:**
```javascript
{
  configurable: false,
  enumerable: true,
  writable: false
}

React.Children模块

Issues ?

import React from 'react';

class Index extends React.Component {
  render() {
    console.log(this.props.children);
    return (<div>
      {this.props.children.sort().join(',')} {/*为啥不能直接调用sort*/}
      </div>)
  }
}

export default function() {
  return (
    <Index>
     {'bananas'}{'oranges'}{'apples'}
    </Index>
  )
}

TypeError: Cannot assign to read only property '1' of object '[object Array]'

children属性是数组了,为啥不能直接调用sort,而非得通过React.Children.toArray转换下

报错原因Type​Error: "x" is read-only props.children数组是只读的,sort方法触发了对只读属性的写操作。