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;
浙公网安备 33010602011771号