React属性与状态

React属性与状态

属性和状态作为组件之间数据流动的途径。

单向数据流

单向数据流:更新 DOM 的数据总是从顶层流下来,用户事件不直接操作 DOM,而是操作顶层数据。这些数据从顶层流下来同时更新了 DOM。这就如同「云腾致雨,露结成霜」一样是大自然的规律。

在React中,数据的流向是单向的——从父节点传递到子节点,因而组件是简单且易于把握的,它们只需要从父节点获取props渲染即可。如果顶层组件的某个prop改变了,React会递归地向下遍历整颗组件树,重新渲染所有使用这个属性的组件。

属性(props)

属性(props):类似 HTML 中的属性,绘制时可在标签中添加属性,然后在组件中通过 this.props.属性名 获取。props属性是父组件控制子组件的单向数据流传输的关键。

使用props注意事项

  1. props类似HTML的属性
  2. props只读,不能使用this.props修改
  3. props用于整个组件树种传递数据和配置
  4. 访问props,需要通过this.props.属性名 获取传递的属性值

属性使用键值对

// 这个键值对可以是字符串:
<Hello name="winty"/>

// 可以是大括号:大括号包裹的求值表达式
<Hello name={123}/>   
<Hello name={"king"}/>

// 可以是一个数组:这样属性拿到的也是一个数组
<Hello name={[1,2,3]}/>   传入数组

// 可传入变量:变量可以在外部定义,在组件内去引用 变量的值可为任何类型
<Hello name={winty}/>   变量

在组件中使用属性

class HelloMessage extends React.Component{
    render() {
      return <h1>Hello {this.props.name}</h1>;
    }
}
ReactDOM.render(<HelloMessage name="John" />, document.getElementById('example')  );

其中props 可以认为是一个配置接口,在使用 HelloMessage 组件的时候,传入的任何html属性都会保存在组件 this.props 中。

属性使用展开定义

var attr={ one:"11", two:"22" }

这样定义的话,理论上使用应该是one={attr.one}这样调用,但是这样写起来比较繁琐,而且如果数据被修改,就需要对应修改相应的赋值,并且无法动态地设置属性,所以react中添加了一种展开语法:

<Hello {...attr}/>    //也就是三个点加上对象名称

这样使用展开语法,react就会自动把对象中的变量和值当作是属性的赋值,所以Hello实际上就拿到了one、two两个属性,如果没有三个点的话,Hello拿到的实际上就是attr对象,使用的时候还需要自己从中取出变量和值

为组件定义默认属性

可以通过如下两种方式来设置属性的默认值。

//方式1:
class Test extends React.Component{
    static defaultProps = {
        name:'everyone'
    }
    constructor(props){
        super(props);
    }
    render(){
        return (<div>{this.props.name}</div>);
    }
}

//方式2:
class Test extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (<div>{this.props.name}</div>);
    }
}
Test.defaultProps = {
    name:'everyone'
}

使用 PropTypes 进行类型检查

注意: 从 React v15.5 开始 ,React.PropTypes 助手函数已被弃用,我们建议使用 prop-types 库 来定义contextTypes。

PropTypes包

名称链接
PropTypes https://www.npmjs.com/package/prop-types

安装

npm install prop-types

引入

import PropTypes from 'prop-types'; // ES6
var PropTypes = require('prop-types'); // ES5 with npm

使用

PropsTypes是React中用来定义props的类型,不符合定义好的类型会报错。建议可复用组件要使用prop验证!接着上面的列子设置PropsTypes如下:

# 写法一:
class Test extends React.Component{
    static defaultProps = {
        name:'everyone'
    }
    constructor(props){
        super(props);
    }
    render(){
        return (<div>{this.props.name}</div>);
    }
}
Test.propTypes = {
    name:PropTypes.string
}

<Test name="'houningzhou'" />


# 写法二:
class Test extends React.Component{
    static defaultProps = {
        name:'everyone'
    }
    static propTypes = {
        name:PropTypes.string
    }
    constructor(props){
        super(props);
    }
    render(){
        return (<div>{this.props.name}</div>);
    }
}


<Test name="'houningzhou'" />
React.PropTypes 提供很多验证器 (validator) 来验证传入数据的有效性。官方定义的验证器如下,不是使用ES6语法。

MyComponent.propTypes = {
    // 可以声明 prop 为指定的 JS 基本类型。默认情况下,这些 prop 都是可传可不传的。
    optionalArray: PropTypes.array,
    optionalBool: PropTypes.bool,
    optionalFunc: PropTypes.func,
    optionalNumber: PropTypes.number,
    optionalObject: PropTypes.object,
    optionalString: PropTypes.string,
    optionalSymbol: PropTypes.symbol,

    // 所有可以被渲染的对象:数字,字符串,DOM 元素或包含这些类型的数组(or fragment) 。
    optionalNode: PropTypes.node,

    // React 元素
    optionalElement: PropTypes.element,

    // 你同样可以断言一个 prop 是一个类的实例。 用 JS 的 instanceof 操作符声明 prop 为类的实例。
    optionalMessage: PropTypes.instanceOf(Message),

    // 你可以用 enum 的方式 确保你的 prop 被限定为指定值。
    optionalEnum: PropTypes.oneOf(['News', 'Photos']),

    // 指定的多个对象类型中的一个
    optionalUnion: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
      PropTypes.instanceOf(Message)
    ]),

    // 指定类型组成的数组
    optionalArrayOf: PropTypes.arrayOf(React.PropTypes.number),

    // 指定类型的属性构成的对象
    optionalObjectOf: PropTypes.objectOf(React.PropTypes.number),

    // 特定形状参数的对象
    optionalObjectWithShape: PropTypes.shape({
      color: PropTypes.string,
      fontSize: PropTypes.number
    }),

    // 你可以在任意东西后面加上 `isRequired` 来确保 如果 prop 没有提供 就会显示一个警告。
    requiredFunc: PropTypes.func.isRequired,

    // 不可空的任意类型
    requiredAny: PropTypes.any.isRequired,

    // 你可以自定义一个验证器。如果验证失败需要返回一个 Error 对象。
    // 不要直接使用 `console.warn` 或抛异常,
    // 因为这在 `oneOfType` 里不起作用。
    customProp: function(props, propName, componentName) {
      if (!/matchme/.test(props[propName])) {
        return new Error('Validation failed!');
      }
    }
};

 

状态(State)

State介绍

状态 state:使用this.state来引用,state本身就是状态的意思,状态指的是事物所处的状况,状况就是环境。

通常使用state存储简单的视图状态,比如说下拉框是否显示、单选 是否选中,或者需要自身去维护的变化数据等。

注意:
状态是事物自己处理的,不和属性一样,属性是天生的,事物一般来说没有办法修改。
状态是事物本身的是事物的私有属性,也就是由自己决定,父组件和子组件都不能改变他。给定了状态就一定知道结果是什么。

组件中用到的某个变量是不是应该作为组件State,可以通过下面的5条依据进行判断:

  1. 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
  2. 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
  3. 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
  4. 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性,例如组件中用到的定时器,就应该直接定义为this.timer,而不是this.state.timer
  5. 这个变量修改后,是否要更新组件?是,那么它是一个状态。

设置默认state

class Test extends React.Component{
    constructor(props){
        super(props);
        //默认状态
        this.state = {
            isShow:true
        }
    }
    render(){
        return <div style={display:this.state.isShow?'block':'none'}>This is component!</div>
    }
}

 

修改state

直接修改state,组件并不会重新重发render。例如:

// 错误
this.state.title = 'React';

state可以通过setState来修改,只要setState被调用,render就会被调用。如果render函数的返回值有变化,虚拟DOM就会更新,真实的DOM也会被更新,最终用户可以在浏览器中看到变化。

this.setState({

})

setState会触发diff算法:判断state和页面结果的区别,是否需要更新

案例

class Timer extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            sec: 1
        }
    }
    add(){
        this.setState({sec:this.state.sec+1});
    },
    componentDidMount(){
        setInterval(this.add,1000);
    },
    render(){
        return ( <div style={this.style}>过去了:{this.state.sec}秒钟</div>);
    }
}
ReactDOM.render(<Timer/>,document.getElementById('demo'));

 

State 的更新是异步的

当我们调用setState时,组件的state病不会立即修改,setState只是把要修改的状态放入到一个队列中,React会优化真正的执行时机,并且出于性能原因,可能会将多次setState的状态修改合并在一次状态修改。所以不要依赖当前的state去计算下一个state。

state 和 props 之间有什么区别?

props 和 state 都是在改变时会触发一次重新渲染的 JavaScript 对象。虽然两者都具有影响渲染输出的信息,但它们在一个重要方面是不同的: props 传递到组件(类似于函数参数),而 state 是在组件内管理的(类似于函数中声明的变量)。

state

不要在state中保存计算出的值,而应该保存简单的数据。

状态:下拉菜单是否显示、输入框的值、变化的数据、选项卡的选中状态

props

props作为数据源存在,使用props在整个组件树中传递数据。

posted @ 2019-08-09 16:34  想赢就别喊疼  阅读(718)  评论(0编辑  收藏  举报