• props & children


    一、 choosing the type at runtime

    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // Wrong! JSX type can't be an expression.
      return <components[props.storyType] story={props.story} />;
    }

    为了解决这个问题,我们将其赋值给首字母大写的变量

    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // Correct! JSX type can be a capitalized variable.
      const SpecificStory = components[props.storyType];
      return <SpecificStory story={props.story} />;
    }

    二、 props in JSX

    this.props引用属性,属性是不可以由组件自己进行修改,组件的属性是由父组件传递进来的。有多种方法指定JSX的props属性

    2.1  键值对形式

    <HelloWorld propName=propValue />

    propValue可以是字符串,大括号包起来的数字或字符串{},大括号包起来的数组{[]},大括号包起来的一个变量,即时函数

    1)JS表达式

    可以传递任何大括号包裹的JS表达式作为props。

    <MyComponent foo={1 + 2 + 3 + 4} />

    对于MyComponent组件,props.foo属性等于10. if语句和for循环不是JS表达式,因此不能直接用于JSX。

    2)字符串

    可以传递一个字符串作为prop,因此下面的两条语句是等价的。

    <MyComponent message="hello world" />
    
    <MyComponent message={'hello world'} />

    2.2 prop默认为true

    下面两种表述是等价的

    <MyTextBox autocomplete />
    
    <MyTextBox autocomplete={true} />

    2.3 defaultProps

    可以通过指定defaultProps属性值来指定prop的默认值,这是用在未定义的props上,但是当props值为null时并不起作用:

    class CustomButton extends React.Component {
      // ...
    }
    
    CustomButton.defaultProps = {
      color: 'blue'
    };
    
     render() {
        return <CustomButton /> ; // props.color will be set to blue
      }
    
    render() {
        return <CustomButton color={null} /> ; // props.color will remain null
      }
    class Greeting extends React.Component {
      render() {
        return (
          <h1>Hello, {this.props.name}</h1>
        );
      }
    }
    
    // Specifies the default values for props: 静态属性 类名.属性名
    Greeting.defaultProps = { 
      name: 'Stranger'
    };
    
    // Renders "Hello, Stranger":
    ReactDOM.render(
      <Greeting />,
      document.getElementById('example')
    );

    defaultProps用来确保当父组件没有提供值时,this.props.name仍然能够取到值,propTypes类型检测发生在defaultProps解析之后,所以类型检测也是适应于defaultProps.

    2.3 扩展运算符

    展开对象的形式,使用...+对象名,React自动看成是多个属性名

    var props={
        one:'123',
        two:321
    }
    <HelloWorld {...props}/>

     要经常使用解构赋值

    class FancyCheckbox extends React.Component{
      render() {
        var { checked, title, ...other } = this.props;
        var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
        var fancyTitle = checked ? 'X ' + title : 'O ' + title;
        return (
          <label>
            <input {...other}
              checked={checked}
              className={fancyClass}
              type="checkbox"
            />
            {fancyTitle}
          </label>
        );
      }
    });

    三、children in JSX

    在拥有开闭标签的JSX表达式中,开闭标签之间的内容传递给了props.children属性,你没办法通过 this.props.children 取得当前组件的子元素。 因为this.props.children 返回的是组件拥有者传递给你的 passed onto you 子节点。

    class App extends React.Component{
      componentDidMount() {
        // This doesn't refer to the `span`s! It refers to the children between
        // last line's `<App></App>`, which are undefined.
        console.log(this.props.children);
      }
    
      render() {
        return <div><span/><span/></div>;
      }
    }
    
    ReactDOM.render(<App></App>, mountNode);

    有多种不同的方法来传递children。

    1)字符串

    开闭标签之间可以是字符串,因此props.children就是这个字符串

    <MyComponent>Hello world!</MyComponent>

    在这里props.children=Hello world!

    JSX会移除空格,因此下面的几种表述是等价的:

    <div>Hello World</div>
    
    <div>
      Hello World
    </div>
    
    <div>
      Hello
      World
    </div>
    
    <div>
    
      Hello World
    </div>

    2)JSX children

    你也可以提供更多的JSX元素作为children,这在嵌套组件中很有用:

    <MyContainer>
      <MyFirstComponent />
      <MySecondComponent />
    </MyContainer>

    你可以混合不同类型的children,因此你可以混合使用字符串和JSX children

    <div>
      Here is a list:
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
      </ul>
    </div>

    3)javascript children

    可以使用任何大括号括起来的JS表达式作为children,比如下面这两种表述是相同的

    <MyComponent>foo</MyComponent>
    
    <MyComponent>{'foo'}</MyComponent>

    这通常用于呈现JSX任意长度列表,比如下面这种呈现一个HTML列表

    function Item(props) {
      return <li>{props.message}</li>;
    }
    
    function TodoList() {
      const todos = ['finish doc', 'submit pr', 'nag dan to review'];
      return (
        <ul>
          {todos.map((message) => <Item key={message} message={message} />)}
        </ul>
      );
    }

    JS表达式还可以跟其他类型的children一起混用,这通常用于字符串模板

    function Hello(props) {
      return <div>Hello {props.addressee}!</div>;
    }

    4)函数

    props.children可以传递任何数据,比如你有一个custom组件,你可以使用一个回调函数作为props.children.

    function ListOfTenThings() {
      return (
        <Repeat numTimes={10}>
          {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
      );
    }
    
    // Calls the children callback numTimes to produce a repeated component
    function Repeat(props) {
      let items = [];
      for (let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
      }
      return <div>{items}</div>;
    }

    5)booleans,null,undefined are ignored

    false,true,null,undefined都是合法的children,他们只是不渲染,下面这些表达式将渲染成同样的

    <div />
    
    <div></div>
    
    <div>{false}</div>
    
    <div>{null}</div>
    
    <div>{true}</div>

    当需要有条件的渲染某个react组件时,这是很有用的,

    <div>
      {showHeader && <Header />}
      <Content />
    </div>

     一些看起来像是false的值,比如说数字0,是会被React渲染的。比如下面这个例子,可能并不是你想象的结果,当props.message是一个空数组时,仍然会渲染:

    <div>
      {props.messages.length &&
        <MessageList messages={props.messages} />
      }
    </div>

    要解决这个问题,就要确保&&逻辑运算符前面的表达式是boolean:

    <div>
      {props.messages.length > 0 &&
        <MessageList messages={props.messages} />
      }
    </div>

    相反地,如果你需要在输出中输出false,true,null,undefined这些值,你需要将他们转化为字符串:

    <div>
      My JavaScript variable is {String(myVariable)}.
    </div>

    谨慎处理props.children

    this.props.children的值有三种可能:如果当前组件没有子节点,他就是undefined;如果有一个子节点,数据类型是object;如果有多个子节点,数据类型就是array。所以处理this.props.children的时候要小心。
    React提供了一个工具方法React.Children来处理this.props.children.

    React.Children.map

    我们可以用React.Children.map来遍历子节点,而不用担心this.props.children的数据类型是undefinde还是object.

    React.Children.map(children, function[(thisArg)])

    在每一个直接子级(包含在 children 参数中的)上调用 function 函数,此函数中的 this 指向 thisArg。如果 children是一个内嵌的对象或者数组,它将被遍历:不会传入容器对象到 function 中。如果 children 参数是 null 或者undefined,那么返回 null 或者 undefined 而不是一个空对象。

    <script type="text/jsx">
        class NotesList extends React.Conponent{
            render(){
                return(
                    <ol>
                        {
                         React.Children.map(this.props.children,function(child){
                                return <li>{child}</li>;
                            })
                        }
                    </ol>
                );
            }
        }
        React.render(
            <NotesList>
                <span>hello</span>
                <span>world</span>
            </NotesList>,
            document.getElementById('example')
        );
    </script>

    React.Children.forEach

    类似React.Children.map(),只是不会返回array

    React.Children.forEach(children, function[(thisArg)])

    React.Children.count

    返回 children 当中的组件总数,和传递给 map 或者 forEach 的回调函数的调用次数一致。

    React.Children.count(children)

    React.Children.only

    返回唯一的子节点,否则报错

    React.Children.only(children)

    React.Children.toArray

    给子节点分配key值,转化为数组形式返回,这个方法在render中操作子节点集合是有用的,尤其是当你想要重新排列或者分割this.props.children时。

    React.Children.toArray(children)

    五、属性和状态对比

    5.1 属性和状态的相似点

    • 都是纯JS对象
    • 都会触发render更新
    • 都具有确定性,给定相同的属性和相同的状态,会有相同的结果

    5.2 属性和状态的不同点

      属性this.props 状态this.state
    能否从父组件获取初始值          能          否
    能否由父组件修改          能          否
    能否在组件内部设置默认值          能          能
    能否在组件内部修改          否          能
    能否设置子组件的初始值          能          否
    能否修改子组件的值          能          否

    状态就是和组件自己相关的,既不和父组件相关也不和子组件相关。

    组件不能修改自己的属性,可以从父组件获得属性,父组件可以修改它的属性,他也可以修改子组件的属性。

    由于this.props和this.state都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,

    this.props 表示那些一旦定义,就不再改变的特性,而 this.state是会随着用户互动而产生变化的特性。

    5.3 简单的区分

    组件在运行时需要修改的数据就是状态。

    比如:用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取.

    文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况

  • 相关阅读:
    BZOJ1864: [Zjoi2006]三色二叉树
    2019牛客全国多校训练四 I题 string (SAM+PAM)
    2019杭电多校第二场
    HDU5919 Sequence II(主席树)
    2019牛客全国多校训练三 题解
    2019牛客多校第二场
    2019 杭电多校第一场 题解
    2019 牛客全国多校一
    POJ3261 Milk Patterns(后缀数组)
    POJ1743 Musical Theme (后缀数组 & 后缀自动机)最大不重叠相似子串
  • 原文地址:https://www.cnblogs.com/YangqinCao/p/6139480.html
Copyright © 2020-2023  润新知