react:组件这么写就好~~

一、创建组件

方法一:构造函数创建组件

注意:

  • 使用构造函数来创建组件,必须要向外return一个合法的JSX创建的虚拟DOM
  • 使用构造函数来创建组件,用props接收外部传进来的数据。
// 使用组件并 为组件传递 props 数据
<Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello>

// 在构造函数中,使用 props 形参,接收外界 传递过来的数据
function Hello(props) {
  // props.name = 'zs'
  console.log(props)
  // 结论:不论是 Vue 还是 React,组件中的 props 永远都是只读的;不能被重新赋值;
  return <div>这是 Hello 组件 --- {props.name} --- {props.age} --- {props.gender}</div>
}

方法二:class关键字创建组件

ES6 中 class 关键字,是实现面向对象编程的新形式;
必须 让自己的组件,继承自 React.Component;
在 组件内部,必须有 render 函数,作用:渲染当前组件对应的 虚拟DOM结构

import React from ‘react’
class 组件名称 extends React.Component {
	constructor(){
		super();
		this.state=['a','b','c'];
	};
    render(){
        // render 函数中,必须 返回合法的 JSX 虚拟DOM结构
        return <div>这是 class 创建的组件</div>
    }
}

两种创建方式的对比

构造函数-无状态组件class关键字-有状态组件
使用场景组件内,不需要有私有的数据时使用。组件内,需要有自己私有的数据。
props 中的数据:都是外界传递到组件中的;都是只读的;存在存在
state 中的数据:都是组件内私有的;都是可读可写的;不存在存在
生命周期函数不存在存在

二、props属性&state状态

1.props属性

  • this.props:获取外部传入的数据
//新建一个组件AddUser.jsx
import React from 'react';

export default Class AddUser extends React.Component {
	render(){
        return (
        	<div class="wrap-adduser">
				{/* this.props:获取外部传入的数据。*/}
				<div>名字:{this.props.name}</div>
				<div>年龄:{this.props.age}</div>
			</div>
		)
    }
}
  • 使用ReactDOM:把组件 render(挂载) 到对应的DOM节点上
let adduer =<div class="wrap-adduser">
				{/* this.props:获取外部传入的数据。*/}
				<div>名字:{this.props.name}</div>
				<div>年龄:{this.props.age}</div>
			</div>
//app.jsx
import {render} from 'react-dom';
import AddUser from './adduser'

const props = {
	name:'张三',
	age:18
};
//render (<AddUser name='张三' age=18>,document.getElementById('container'));
//下面的写法是JSX利用ES6语法生成的遍历的功能------属性扩散
render (<AddUser {...props}>,document.getElementById('container'));
  • 验证props传入的属性:使用react中的PropTypes验证数据类型
import {PropTypes} from 'react';

const propTypes = {
//验证不同类型的JS变量
	optionalArray:PropTypes.array,
	optionalBool:PropTypes.bool,
	optionalFunc:PropTypes.func,
	optionalNumber:PropTypes.number,
	optionalObject:PropTypes.object,
	optionalString:PropTypes.string,
	
//可以是一个ReactElement类型
	optionalElement:PropTypes.element,
	
//可以是别的组件的实例
	optionalMessage:PropTypes.instanceOf(Message),
	
//可以规定一组值其中的一个
	optionalEnum:PropTypes.oneOfType(['News','Photos']),
	
//可以规定一组类型中的一个
	optionalUnion:PropTypes.oneOfType([
		PropTypes.string,
		PropTypes.number,
		PropTypes.oneOfType(Message)
	]),
	
//可以在最后加一个isRequired,表明这个属性是必需的,否则会返回一个错误
requiredFunc:React.PropTypes.func.isRequired
}

在接收props数据的组件中添加验证

import React ,{PropTypes} from 'react';
//需要验证的属性
const propTypes ={
	name:PropTypes.string.isRequired,
	gender:PropTypes.number.isRequired
};

class AddUser extends React.Component {
	render(){
        return (
        	<div class="wrap-adduser">
				{/* this.props:获取外部传入的数据。*/}
				<div>名字:{this.props.name}</div>
				<div>年龄:{this.props.age}</div>
			</div>
		)
    }
}
//将验证赋值给AddUser这个组件的propTypes属性
AddUser.propTypes=propTypes ;

export default AddUser;

2.state状态

  • constructor中用this.state 定义它的值,根据值来渲染不同的UI;
  • 当state的值发生改变时,可通过 this.setState方法让组件再次调用render方法,再次渲染UI。

例:点赞功能:点击一次,赞的次数加1

//Good.jsx
export default class Good extends React.Component {
	constructor (props) {
		super(props);
		//定义初始的值
		this.state={
			linked:0
		};
		//改变this的指向
		this.linkedCB=this.linkedCB.bind(this);
	}
}

linkedCB(){
	let linked=this.state.linked;
	改变初始的值,并渲染页面
	linked++;
	this.setState({
		linked
	})
}

render(){
	return(
		<div>
			<button onClick={this.linkedCB}> 点个赞吧 </button>
			<span>点赞总数:{this.state.linked}</span>
		</div>
	)
}

注意:React组件通过props和state的值,使用render方法生成一个组件的实例

  • 什么组件应该有state,而且应该遵循最小化state的准则?即让大多数的组件处于无状态的。
  • 创建尽量多的无状态组件,这些组件只关心渲染数据;
  • 这些组件的外层是一个包含state的父级组件,这个组件用于处理各种事件,交流逻辑,修改state;对应的子组件只要关心传入的属性就好。
  • state应该包含什么数据?不应该包含什么数据?
  • 应该包含的数据:包含组件的事件回调函数可能引发UI更新的这类数据。且根据最小化设计state的原则,当数据有交叉的部分时,小范围的数据只需保存ID或索引就好。

  • 不应该包含的数据:

    • 可以由state计算得出的数据。(小范围的数据)
    • 组件。(不需要保存到state,只用在render函数中渲染就好)
      *props中的数据。(props可以看做是组件的数据源,它不需要保存到state中)

3.state中的值(单向数据流)

  • 在 React 中,默认只是单向数据流,也就是 只能把 state 上的数据绑定到 页面,无法把 页面中数据的变化,自动同步回 state 。
  • 如果需要把 页面上数据的变化,保存到 state,则需要程序员手动监听文本框的onChange事件,拿到最新的数据,手动调用this.setState({ }) 更改回去;
  • 案例
<input type="text" style={{ width: '100%' }} value={this.state.msg} onChange={() => this.textChanged()} ref="mytxt" />

 // 响应 文本框 内容改变的处理函数
  textChanged = () => {
    // console.log(this);
    // console.log(this.refs.mytxt.value);
    this.setState({
      msg: this.refs.mytxt.value
    })
  }

三、组件的生命周期

组件初始化

  • getDefaultProps:只在装载前调用一次;
  • getInitialState:只在装载前调用一次,这个函数的返回值会被设置到this.state中;
  • componentWillMount:在render之前调用,可做渲染前的一些准备;
  • render
  • componentDidMount:只在装载完成后调用一次,render之后执行,在这里可以获得到组件的DOM结构。相当于vue中的mounted。

组件props更新

当组件接收到新的props时,会依次触发下面的方法

  • componentWillReceiveProps(object,nextProps):接收到新的props时触发,nextProps即为新的的props,this.props为旧的props。
  • shouldComponentUpdate:重新调用render之前执行,返回一个布尔值,返回false则组件不会被更新,之前的流程都不会被触发,默认返回true,组件更新。
  • componentWillUpdate:在render之前调用,可做渲染前的一些准备,与componentWillMount类似。
  • render
  • componentDidUpdate:重新渲染完成后立刻调用,类似于componentDidMount。

组件卸载

-componentWillUnmount:组件卸载和销毁之前调用的方法。

四、组件的组合使用

例.渲染一个爱好列表

//Hobby.jsx 子组件
import React,{PropTypes} from 'react';
const propTypes={
	hobby:Proptype.string.isRequired
};

class Hobby extends ReactComponent(){
	render(){
		return <li>{this.props.hobby}</li>
	} 
} 
Hobby.propTypes=propTypes;
export default Hobby;
//HobbyLIst.jsx 父组件
import Hobby from './hobby';

...
constructor(props){
	super(props);
	//在state中添加两个爱好
	this.state = {
		linked:0,
		hobbies:['music','dance']
	};
}
...
render(){
	return (
	<div>
        <h2>爱好列表</h2>
        <ul>
            {this.state.map((hobby,k)=>
            	<Hobby key={k} hobby={hobby} />
            )}
        </ul>
    </div>
	)
}

注意:要给每个循环组件添加一个唯一的key值。

五、DOM操作

在大多数情况下,不需要进行DOM操作去更新UI,应该使用setState来重新渲染UI。但是有一些特殊情况,确实 需要访问一些DOM结构:可以采用refs的方式获得DOM节点

//例.添加爱好 HobbyList.jsx
render() {
        return(
            <div>
            	...
                <input type="text" ref="addhobby">
                <button onclick={this.addHobbyCB}>点击添加爱好</button>
            </div>
        )
}
...
addHobbyCB(){
        // 用this.refs.name来获取DOM节点
        let hobbyInput=this.refs.hobby;
        let val = hobbyInput.value;
        if (val) {
            let hobbies = this.state.hobbies;
            // 添加值到数组中
            hobbies=[...hobbies,val];
            // 更新state,熏染UI
            this.setState({hobbies},()=>{hobbyInput.value='';})
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值