fullstack react 学习笔记(三)使用props/state/children等配置组件

一、主要内容介绍

reactComponent

包含两方面内容:

render():至少应该包含一个render()方法,返回一个reactElement;

绑定处理方法:绑定时间、设置state,或者与children进行交互。

主要的内容:

1、render()

2、props

3、context

4、state

5、Stateless Component

6、children

7、statics

8、ReactComponent

1、ReactComponent:

可以使用两种方式创建reactCOmponent

方式一:

import React from 'react';
import createReactClass from 'create-react-class';

// React.createClass
const CreateClassApp = createReactClass({
  render: function() {} // required method
});

export default CreateClassApp;

  

 

方式二:

import React from 'react';

// ES6 class-style
class ComponentApp extends React.Component {
  render() {} // required
}

export default ComponentApp;

  

2、render()

component只返回一个element,可以是虚拟的DOM,也可以是null或者false,react自动解释为<noscript />

在render()中获取数据:

使用输入的参数props,或者是本地化的状态state,也可以是context获取全局的参数

3、props

props是由上一级的Component传递给下一级的参数,下一级可以使用this.props获取父级别传递的参数。props是不可变的。

我们可以使用props传递函数、javascript对象、基本元素(数值、字符串等)、reactElement和虚拟的DOM节点

我们可以使用PropTypes限制传递的参数

4、PropTypes

使用prop-types包引入PropTypes,然后在Component中使用static propTypes定义props对应的数据类型。

import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';

class MapComponent extends React.Component {
  static propTypes = {
    lat: PropTypes.number,
    lng: PropTypes.number,
    zoom: PropTypes.number,
    place: PropTypes.object,
    markers: PropTypes.array
  };

  PropTypes内置的类型有:

number、

string、

bool(boolean)、

func(function),

object、

shape(object shape)、

多种类型(oneOf()限制具体的值、oneTypeOf()限制不同的类型)

instanceOf:类的实例

array

arrayOf():数组中的元素必须是对应的数据类型

node:numbers,string ,DOM,Element,arrays,fragment

element

any

可选还是必须:isRequired

自定义验证函数

5、使用默认的props

使用static defaultProps

class MapComponent extends React.Component {

  static defaultProps = {
    lat: 37.773972,
    lng: -122.431297,
    zoom: 10,
    markers: [
      {lat: 37.773972, lng: -122.431297, title: 'San Francisco'},
      {lat: 37.8719, lng: -122.2585, title: 'Berkeley, CA'}
    ]
  };

  

6、context

context类似于全局变量,因此你可以无需和props一样从上到下逐个传递,而是可以在任意需要的子元素中获取。

由于context具有试验性质,因此项目中应该尽可能少的使用context

使用:

在父一级使用:childContextTypes和getChildContext

在需要获取context的子节点中:contentTypes

class Messages extends React.Component {
  static propTypes = {
    users: PropTypes.array.isRequired,
    initialActiveChatIdx: PropTypes.number,
    messages: PropTypes.array.isRequired,
  };

  static childContextTypes = {
    users: PropTypes.array,
    userMap: PropTypes.object,
  };

  static defaultProps = {
    initialActiveChatIdx: 0,
  };

  state = {
    currentChatIndex: this.props.initialActiveChatIdx,
  };

  getChildContext() {
    return {
      users: this.getUsers(),
      userMap: this.getUserMap(),
    };
  }

  getUsers = () => {
    const users = this.props.users
      .map(m => pick(m, [ 'uuid', 'username', 'avatar', 'lastOnline' ]))
      .sort((a, b) => moment(a.lastOnline).isBefore(b.lastOnline));
    return users;
  };

  getUserMap = () => {
    // Should be elsewhere
    return this.props.users.reduce(
      (memo, u) => {
        memo[u.uuid] = u;
        return memo;
      },
      {}
    );
  };

  

在子节点中:

import PropTypes from 'prop-types';
import React from 'react';
import moment from 'moment'
const styles = require('./Messages.css');
// For demo purposes

class ThreadList extends React.Component {
  
  static contextTypes = {
    users: PropTypes.array,
  };

  componentWillReceiveProps(nextProps, nextContext) {
    // ...
  }
  
  shouldComponentUpdate(nextProps, nextState, nextContext) {
    // ...
  }

  componentWillUpdate(nextProps, nextState, nextContext) {
    // ...
  }

  componentDidUpdate(prevProps, prevState, prevContext) {
    // ...
  }

  render() {
    return (
      <div className={styles.threadList}>
        <ul className={styles.list}>
          {this.context.users.map((u, idx) => {
            return (
              <UserListing
                onClick={this.props.onClick}
                key={idx}
                index={idx}
                user={u}
              />
            );
          })}
        </ul>
      </div>
    );
  }
}

export default ThreadList

  如果子节点中使用的context,在lifecycle方法中将增加第三个参数nextContext,在stateless Component中作为第二个参数

注意:谨慎使用context

7、state

state存储可变数据:

一、该数据无法通过其他Component传递

二、该数据无法通过计算获得

使用原则:state尽可能的少

import React, { PropTypes } from 'react';
import styles from '../Switch.css';

const CREDITCARD = 'Creditcard';
const BTC = 'Bitcoin';

class Switch extends React.Component {
  state = {
    payMethod: BTC,
  };

  select = (choice) => {
    return (evt) => {
      this.setState({
        payMethod: choice,
      });
    };
  };

  renderChoice = (choice) => {
    // create a set of cssClasses to apply
    const cssClasses = [];

    if (this.state.payMethod === choice) {
      cssClasses.push(styles.active); // add .active class
    }

    return (
      <div
        className='choice'
        onClick={this.select(choice)}
        className={cssClasses}
      >
        {choice}
      </div>
    );
  };

  render() {
    return (
      <div className='switch'>
        {this.renderChoice(CREDITCARD)}
        {this.renderChoice(BTC)}
        Pay with: {this.state.payMethod}
      </div>
    );
  }
}

module.exports = Switch;

  注意:onClick要求的是返回一个function,因此执行select()函数返回的还是一个函数。这是绑定事件传递参数的固有写法。

使用props初始化state最好在constroctor中,初始化只有一次。

更新状态,如果更新状态依赖上一次的state,则最好在setState中使用方法调用上一个prevState,而不是使用对象,因为setState是异步执行的,如果上一次setState还没有生效的情况下,再次调用setState,这时的state还是原来的state.,这样就造成了使用者调用了两次setState,而结果只是一次调用的结果。

import PropTypes from 'prop-types';
import React, {Component} from 'react';

const counterStyle = {
  width: '50px',
  textAlign: 'center',
  backgroundColor: 'aliceblue',
  padding: '10px'
};

class Counter extends Component {
  constructor(props) {
    super(props);

    this.state = {
      value: this.props.initialValue
    };

    this.increment = this.increment.bind(this);
    this.decrement = this.decrement.bind(this);
  }

  decrement = () => {
    this.setState(prevState => {
      return {
        value: prevState.value - 1
      };
    });
  };

  increment = () => {
    this.setState(prevState => {
      return {
        value: prevState.value + 1
      };
    });
  };

  render() {
    return (
      <div style={counterStyle} key="counter">
        {this.state.value}
        <p>
          <button onClick={this.increment}>+</button>
          <button onClick={this.decrement}>-</button>
        </p>
      </div>
    );
  }
}

Counter.propTypes = {
  initialValue: PropTypes.number
};

Counter.defaultProps = {
  initialValue: 120
};

export default Counter;

  如果state遍布项目的所有节点,那么维护将变得异常困难,一个好的方法是我们只使用一个stateful Component,其他的Component全部为stateless Component.

8、stateless Component

import React from 'react'

const Header = function(props) {
  return (<h1>{props.headerText}</h1>)
}

export default Header

  stateless Component其实是一个function,接受props作为参数,函数中不能使用this.

无状态组件可以使得reactApp轻量化,并且具有较快的反映速度。

在stateless Component中无法调用生命周期函数,可以使用PropTypes和defalutProps;

尽可能的使用无状态组件。

使用无状态组件便于重用。

9、this.props.children

children 是react内置的一个props属性,子元素可以是一个,也可以是多个,如果是一个的的话那么childeren传递的是一个element,否则的话是一个array

import PropTypes from 'prop-types';
import React from 'react';

class DocumentedContainer extends React.Component {
  static propTypes = {
    children: PropTypes.oneTypeOf([PropTypes.element, PropTypes.array])
  };

  render() {
    return <div className="container">{this.props.children}</div>;
  }
}

export default DocumentedContainer;

  如果要限制子元素个数,可以使用

import PropTypes from 'prop-types';
import React from 'react';

class SingleChildContainer extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired
  };

  render() {
    return <div className="container">{this.props.children}</div>;
  }
}

export default SingleChildContainer;

  

第二种方式是使用React.Children.map()或React.Children.forEach()

map返回一个数组,而each不返回,

import PropTypes from 'prop-types';
import React from 'react';

class MultiChildContainer extends React.Component {
  static propTypes = {
    component: PropTypes.element.isRequired,
    children: PropTypes.element.isRequired
  };

  renderChild = (childData, index) => {
    return React.createElement(
      this.props.component,
      {}, // <~ child props
      childData // <~ child's children
    );
  };

  render() {
    return (
      <div className="container">
        {React.Children.map(this.props.children, this.renderChild)}
      </div>
    );
  }
}

export default MultiChildContainer;

  

React.Childern.toArray()

import PropTypes from 'prop-types';
import React from 'react';

class ArrayContainer extends React.Component {
  static propTypes = {
    component: PropTypes.element.isRequired,
    children: PropTypes.element.isRequired
  };

  render() {
    const arr = React.Children.toArray(this.props.children);

    return <div className="container">{arr.sort((a, b) => a.id < b.id)}</div>;
  }
}

export default ArrayContainer;

  

 

posted @ 2018-08-10 18:34  tutu_python  阅读(386)  评论(0)    收藏  举报