React组件

React的首要思想是通过组件(Component)来开发应用,组件简单点讲就是指能够完成特定功能的独立,可复用的代码。

先来一个列子一个计时器的例子

点击按钮数字增加(当时学习深入浅出React和Redux 的一个小例子)

主要的信息通过注解写进代码里就不在陈述

首先在src下面创建一个ClickCounter.js的js文件

这里直接使用之前创建的那个react项目

首先贴出index.js代码

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
// 使用import导入了ClickCounter组件
import ClickCounter from './ClickCounter'
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
    //引入ClickCounter
    <ClickCounter/>,
    document.getElementById("root")
);
registerServiceWorker();

在这里ReactDom.render的第一个参数<ClickCounter/>就是一段jsx代码 ,React官网有对于JSX的介绍!ps:React判断一个元素是HTML元素还是React组件的原则就是看第一个字母是否是大写,如果我们在JSX中不用ClickCounter而是clickCounter,那就得不到我们想要的结果

然后在贴出ClickCounter.js的代码

//import React,{Component} from 'react';从react库中引入了React和Component
//Component作为所有的基类,提供了很多组件共有的工能
//引入React虽然我们没有使用,但是一定要导入这个React,
// 这是因为JSX最终会被编译成依赖于react的表达式
import React,{Component} from 'react';
//使用es6来创建一个叫ClickCounter的组件类,继承于Component
//ps: 在react出现支出使用的是React.createClass方式来创建组件类,
// 这种方式是一种过时的方法现在使用es6语法创建
class ClickCounter extends  Component {
    constructor(props) {
        super(props);
        this.onClickButton = this.onClickButton.bind(this);
        this.state = {count:0};
    }
    onClickButton() {
        this.setState({count: this.state.count + 1});
    }
    render() {
        //定义样式
        const counterStyle = {
            margin:"20px",
            color: 'green'
        }
        return (
            //这个div引用我了counterStyle样式
            <div style={counterStyle}>
                <div>
                    Click Count:{this.state.count}
                </div>
                <button onClick={this.onClickButton}>点击我</button>

            </div>
        );
    }
} export default ClickCounter;

1.props

接下来看第二个例子父组件与子组件相互传值

我们现在新增了两个js,ControlPanel.js和Counter.js两个js组件,其中CounterPanel是Counter的父组件

首先贴出ControlPanel的代码

import React, { Component } from 'react';
import Counter from './Counter.js';

const style = {
    margin: '20px'
};

class ControlPanel extends Component {
    render() {
        console.log('enter ControlPanel render');
        return (
            <div style={style}>
                {/*调用Counter不传参数*/}
                <Counter caption="First"/>
                {/*调用Counter组件传入initialValue = 10*/}
                <Counter caption="Second" initialValue={10} />
                {/*调用Counter组件传入initialValue = 20*/}
                <Counter caption="Third" initialValue={20} />
                <button onClick={ () => this.forceUpdate() }>
                    Click me to re-render!
                </button>
            </div>
        );
    }
}

export default ControlPanel;

在ControlPanel里面分别调用了三个counter组件,同时传入不同的参数值

 

 

import React,{Component} from 'react';
import PropTypes from 'prop-types';
const buttonStyle = {
    margin: '10px'
};

class Counter extends Component{

    constructor(props){

        // 如果一个组件需要定义自己的构造函数,
        // 一定要集合在狗仔函数的第一行通过super调用父类也就是React.component的构造函数,
        // 如果在构造函数中没有调用superi(props),那么组件实例被构造之后,
        // 类实例的成员函数就无法通过this.props访问到父组件传的值
        //ps:给this.props赋值是React.Component构造函数的工作之一
        //es6方法创建的React组件不能自动给我们绑定this到当前实例对象
        super(props);
        this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
        this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
        this.state = {
            count:props.initialValue

        }
    }
    // 实现按钮加一
    onClickIncrementButton() {
        this.setState({count: this.state.count + 1});
    }
    // 实现按钮减一
    onClickDecrementButton() {
        this.setState({count: this.state.count - 1});
    }

    render(){
        const {caption} = this.props;
        return(
            <div>
                <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
                <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
                <span>{caption} count:{this.state.count}</span>
            </div>
        )
    }
}
// 在ES6方式定义的组件类中,可以通过增加类的propTypes书记邢来定义prop规格,
// 这不仅是一种声明,而且还是一种限制
Counter.propTypes = {
    caption: PropTypes.string.isRequired,
    initialValue: PropTypes.number
};
// 给变量附上默认值
Counter.defaultProps = {
    initialValue: 0
};
export default Counter;

 如果一个组件需要定义自己的构造函数, 一定要集合在狗仔函数的第一行通过super调用父类也就是React.component的构造函数,类实例的成员函数就无法通过this.props访问到父组件传的值ps:给this.props赋值是React.Component构造函数的工作之一s6方法创建的React组件不能自动给我们绑定this到当前实例对象

  可以看到我们的项目

second我们传入参数10 

thrid 我们传入参数20

 

propTypes

在ES6方式定义的组件类中,可以通过增加类的propTypes书记邢来定义prop规格, 这不仅是一种声明,而且还是一种限制

propTypes的使用:

1.先引入propTypes

import PropTypes from 'prop-types';

2.基础代码  ps:PropTypes.number你想要定义的格式,.isRequired是指是否必须穿这个参数

Counter.propTypes = {
    caption: PropTypes.string.isRequired,
    initValue: PropTypes.number
};

接下来我们修改ControlPanel的代码传入caption属性参数为int类型

    {/*调用Counter组件传入initialValue = 20*/}
                <Counter caption={20}  initialValue={20} />

接下来我们可以在浏览器的Console窗口看到错误

接下来我们继续修改ControlPanel的代码删除caption属性

    {/*调用Counter组件传入initialValue = 20*/}
                <Counter initialValue={20} />

我们可以看到这里上面的爆出类型错误,下面则是没有传递该属性的错误

当然我们使用PropTypes是为了方便我们在开发过程中有一些不必要的错误,如果我们在生产环境就不需要这PropTypes了,使用PropTypes也会消耗一些cpu的资源

2.state

在React中驱动组件渲染过程除了prop,还有state,state代表组件的内部状态,由于React组件不能修改传入的prop,所以需要记录自身的数据变化,就要使用state ps:学过vue的话感觉state就像是vue里面data

下面是对state的初始化

      this.state = {
            count:props.initialValue

        }

如果我们想修改组件的state就必须使用this.setState函数,而不能直接去修改this.stare

prop和state的对比

prop用于定义外部接口,state用于记录内部状态;

 

prop的赋值在外部世界使用组件时,state的赋值在组件内部;
·组件不应该改变prop的值,而state存在的目的就是让组件来改变的。
组件的state,就相当于组件的记忆,其存在意义就是被修改,每一次通过this.setState函数修改state就改变了组件的状态,然后通过渲染过程把这种变化体现出来。

3.子组件向父组件传值

 

首先贴出ControlPanel的代码

 

import React, { Component } from 'react';
import Counter from './Counter.js';

const style = {
    margin: '20px'
};

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

        this.onCounterUpdate = this.onCounterUpdate.bind(this);

        this.initValues = [ 0, 10, 20];

        const initSum = this.initValues.reduce((a, b) => a+b, 0);
        this.state = {
            sum: initSum
        };
    }

    onCounterUpdate(newValue, previousValue) {
        const valueChange = newValue - previousValue;
        this.setState({ sum: this.state.sum + valueChange});
    }

    render() {
        console.log('enter ControlPanel render');
        return (
            <div style={style}>
                {/*调用Counter不传参数*/}
                <Counter onUpdate={this.onCounterUpdate} caption="First"/>
                {/*调用Counter组件传入initialValue = 10*/}
                <Counter onUpdate={this.onCounterUpdate} caption="Second" initialValue={10} />
                {/*调用Counter组件传入initialValue = 20*/}
                <Counter onUpdate={this.onCounterUpdate} caption="threed" initialValue={20} />
                <hr/>
                <div>Total Count: {this.state.sum}</div>
                {/*<button onClick={ () => this.forceUpdate() }>*/}
                    {/*Click me to re-render!*/}
                {/*</button>*/}
            </div>
        );
    }
}

export default ControlPanel;

 

主要新增了onCounterUpdate函数和和onUpdate的调用

接下来是counter的代码

import React,{Component} from 'react';
import PropTypes from 'prop-types';
const buttonStyle = {
    margin: '10px'
};

class Counter extends Component{

    constructor(props){

        // 如果一个组件需要定义自己的构造函数,
        // 一定要集合在狗仔函数的第一行通过super调用父类也就是React.component的构造函数,
        // 如果在构造函数中没有调用superi(props),那么组件实例被构造之后,
        // 类实例的成员函数就无法通过this.props访问到父组件传的值
        //ps:给this.props赋值是React.Component构造函数的工作之一
        //es6方法创建的React组件不能自动给我们绑定this到当前实例对象
        super(props);
        this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
        this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
        this.state = {
            count:props.initialValue

        }
    }
    // 实现按钮加一
    onClickIncrementButton() {
        this.setState({count: this.state.count + 1});
        this.updateCount(this)
    }
    // 实现按钮减一
    onClickDecrementButton() {
        this.setState({count: this.state.count - 1});
        this.updateCount(false)
    }
    updateCount(isIncrement){
        const previousValue = this.state.count;
        const newValue = isIncrement?previousValue+1:previousValue -1;
        this.setState({count:newValue})
        this.props.onUpdate(newValue,previousValue)
    }
    render(){
        const {caption} = this.props;
        return(
            <div>
                <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
                <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
                <span>{caption} count:{this.state.count}</span>
            </div>
        )
    }
}
// 在ES6方式定义的组件类中,可以通过增加类的propTypes书记邢来定义prop规格,
// 这不仅是一种声明,而且还是一种限制
Counter.propTypes = {
    caption: PropTypes.string.isRequired,
    initialValue: PropTypes.number,
    onUpdate: PropTypes.func
};
// 给变量附上默认值
Counter.defaultProps = {
    initialValue: 0,
    onUpdate:f => f
};
export default Counter;

 

主要提取了共同部分到updateCounth函数里, 然后通过调用this.props.onUpdate这个函数向父组件传递数据

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值