组件数据
React 中三种数据应用类型
- Props
- State
- Context
Props
可以是任何类型
props 就是属性 prototype 的缩写,在 JSX 中 props 就像 HTML 的 attribute 一样。在概念上 props 对于组件,就相当于 js 当中的参数对应函数一样。组件函数接收 props 作为参数,然后返回视图的内容。props 比起原生的 html 属性强大许多,可以传入变量、函数、组件 ...
//Function
Component(props) = View
//JSX
const SimpleButton = props => <button className={props.color}>Submit</button>
ReactDOM.render(<SimpleButton color="blue"/>,document.getElementById('app'))
//HTML
<button class="blue">Submit</button>
自上向下传递,自读不可修改
Props 的值自上向下传递,从父组件传入到子组件当中,并且 props 是自读的,不能在组件内部修改 props 的内容。
const Children = props => <p>{props.name}</p>
const Father = <Children name="Bob"/>
拥有类型检查和默认值
Props 有类型检查和默认值,通过 prop-types 设置。
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const Title = props => <h1>{props.title}</h1>
Title.defaultProps = {
title: 'Hello world!'
}
Title.propTypes = {
title: PropTypes.string.isRequired
}
ReactDOM.render(<Title/>,document.getElementById('root'))
State
state 翻译过来可以为状态,一个组件可以有自身的状态,也可以包含整个 react 应用的状态。
- 初始化
- setState方法设置
- 向下传递数据
- 多个组件共用的 State 存放在其公有的父组件里
简单的计数器例子
- 通过 class 类定义组件来声明一个有状态组件
- 然后在构造方法中初始化状态的 state 并为它赋默认值
- 再添加一个负责处理 state 变化的函数 addOne
- 通过 setState 的方法来改变 state 值。
import React from 'react'
import ReactDOM from 'react-dom'
class Counter extends React.Component {
constructor(props) {
super(props)
this.state = {
counter:0
}
}
addOne() {
this.setState({
counter:this.state.counter +1
})
}
render() {
return(
<div>
<p>{this.state.counter}</p>
<button onClick={()=>this.addOne()}>Increment</button>
</div>
)
}
}
ReactDOM.render(<Counter />,document.getElementById('root'))
复杂点的点赞例子,通过点击切换星星状态。
import React from 'react'
import ReactDOM from 'react-dom'
const Title = props => <h1>{props.title}</h1>
const UserInfo = props => <p>{props.firstName + ' ' + props.lastName}</p>
class LikeButton extends React.Component {
constructor(props) {
super(props)
}
render() {
return <button onClick={this.props.handleClick}>{this.props.mark}</button>
}
}
class App extends React.Component {
constructor(props){
super(props)
this.state = {
mark:'☆'
}
}
handleButtonClick(){
const mark = (this.state.mark === '☆') ? '★' : '☆';
this.setState({
mark:mark
})
}
render() {
return (
<div>
<Title title="Hello , jikexueyuan"/>
<UserInfo firstName="Jax" lastName="Chu" />
<LikeButton mark={this.state.mark} handleClick={this.handleButtonClick.bind(this)} />
</div>
)
}
}
const Root = props => <div className="container">{props.children}</div>
ReactDOM.render(
<Root>
<App/>
</Root>
,document.getElementById('root'))
假如 State 分散到应用的各个部分,有的复杂后端数据的交互,有的处理用户输入,有的负责页面变化的逻辑,后期维护是相当困难的。因此在开发 React应用中,我们应尽量把 State统一管理,通过 props 把 state 的数据传递到组件当中。
例子:货币汇率转换器
import React from 'react'
import ReactDOM from 'react-dom'
class CurrencyConvertor extends React.Component {
constructor(props) {
super(props)
this.state = {
money : 100
}
}
handleInputChange(event) {
this.setState({
money:event.target.value
})
}
render() {
return (
<div>
<h2>货币兑换</h2>
<YuanInput money={this.state.money} handleChange={(e)=> this.handleInputChange(e)} />
<MoneyCovertor type='美元' unit='dollar' money={this.state.money} rate={0.1453} />
<MoneyCovertor type='日元' unit='yen' money={this.state.money} rate={16.1814} />
</div>
)
}
}
class YuanInput extends React.Component {
constructor(props){
super(props)
}
handleChange(event){
this.props.handleChange(event)
}
render() {
return (
<p>
<lable>
人民币
<input name='yuan' onChange={(e)=>this.handleChange(e)} value={this.props.money} />
</lable>
</p>
)
}
}
const MoneyCovertor = props => (
<p>
<lable>
{props.type}
<input name={props.unit} value={(props.money * props.rate).toFixed(2)} disabled />
</lable>
</p>
)
ReactDOM.render(<CurrencyConvertor /> ,document.getElementById('root'))
Context
集中管理 state 会引发另一个问题,state 的数据都是自上而下传递的,假如我们在最外一层进行组件管理,而我们使用的子组件确在N层之下,那么我们就需要在每一层的组件都传递 props 下去。所以 React提供 Context 带有实验性质,用于跨层级传递数据。
Context 必须进行类型检查。
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const UserInfo = (props,context) => {
console.log(props,context)
return(
<div className="UserInfo-name">{context.lastName +','+ props.firstName}</div>
)
}
UserInfo.contextTypes = {
lastName:PropTypes.string
}
const Column = props => <div className='column'><UserInfo firstName={props.firstName} /></div>
const Row = props => <div className='row'><Column firstName={props.firstName} /></div>
const Container = props => <div className='container'><Row firstName={props.firstName} /></div>
class App extends React.Component {
constructor() {
super()
this.state = {
firstName: 'Chu',
}
}
getChildContext() {
return {
lastName: 'Jax'
}
}
render() {
return (
<div className="app">
<Container firstName={this.state.firstName} />
</div>
)
}
}
App.childContextTypes = {
lastName: PropTypes.string
}
ReactDOM.render(<App/>,document.getElementById('root'))