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元素都屬於這種情況

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM