目录
一、React 组件
1、定义单个组件
(1)定义组件
(2)使用组件
2、定义复合组件
二、 React Props
1、定义和使用props 传值
- 通过React**类定义**组件时:
通过React**函数定义** 组件时:
2、默认Props
3、多属性传值
三、React State
1、如何定义State
2、setState设置状态
3、State 与 Props 区别
4、state/props 实现父子组件通信
组件一共有两种:有状态和无状态
React.js 中一切皆组件,用 React.js 写的其实就是 React.js 组件。
我们在编写 React.js 组件的时候,一般都需要继承 React.js 的 Component(类定义)。一个组件类必须要实现一个 render 方法,这个 render 方法必须要返回一个 JSX 元素。
但这里要注意的是,必须要用一个外层的 JSX 元素把所有内容包裹起来。(有一个根元素)
返回并列多个 JSX 元素是不合法的。
方式1:通过React自定义组件(DOM元素):**类定义**
import React, {Component} from 'react';
class MyApp extends Component {
}
import React from 'react';
class MyApp extends React.Component {
constructor(props){
super(props);
this.msg="hello,react"
}
render() {
return (
{this.msg}
这是标题2
这是标题2
);
}
}
export default MyApp;
方式2:通过React自定义组件(DOM元素):**函数定义**
import React from 'react';
//箭头函数
const MyApp = () => 这是一个段落
;
export default MyApp;
//普通函数
function Welcome(props) {
return Hello, {props.name}
;
}
export default Welcome;
方式3:**不建议使用**,React.createClass创建组件的方式在react 16版本中去除。
var MyApp = React.createClass({
render: function() {
return Hello World!
;
}
});
import React from 'react';
import ReactDOM from 'react-dom';
import MyApp from './js/MyApp.js'; //导入自定义组件
ReactDOM.render( , document.getElementById('root'));
我们可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离
import React from 'react';
import ReactDOM from 'react-dom';
class WebSite extends React.Component {
render() {
return (
);
}
}
//局部组件Name
class Name extends React.Component {
render() {
return (
{this.props.name}
);
}
}
//局部组件Link
class Link extends React.Component {
render() {
return (
{this.props.site}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
)
React 的一大特点是 单向数据流 。
React 中的每一个组件,都包含有一个属性(props),**属性主要是从父组件传递给子组件的**,在组件内部,我们可以通过this.props获取属性对象。
- 在父组件render 方法中调用组件时使用**key/value** 的形式来指定属性。
- 在自定义子组件中通过**this.props.key** 来获得组件属性的值,需要使用{}括起来。(类可以有props属性,是因为类继承了官方react的组件,函数就没有props属性)
// 类定义组件时,使用属性 this.props.属性名称
class MyApp extends React.Component {
render() {
return ({this.props.name}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
- 在父组件render 方法中调用组件时使用**key/value** 的形式来指定属性。
- 在自定义子组件中通过函数接收参数**props**,**props.key**来获得组件属性的值,需要使用{}括起来
// 函数定义组件时,在组件内部使用属性值:props.属性名称
function Welcome(props) { // 函数需要传递一个参数props
return({props.title}
)
}
ReactDOM.render(
,
document.getElementById('root')
);
定义默认props :
class MyApp extends React.Component {
render() {
return this is my {this.props.name}
}
}
//由于是用ES6 class语法创建组件,其内部只允许定义方法,而不能定义属性,class的属性只能定义在class之外。所以defaultProps要写在组件外部。
MyApp.defaultProps = {
name: 'xxx'
};
ReactDOM.render(
,
document.getElementById('root')
);
(1)定义一个this.props对象,在对象中声明多个**键值对**,用于表示组件的属性
(2)在组件中使用**{...this.props}**的方式传递属性。
“...”表示JSX的延展操作符,这种方式可以很方便的为组件指定多个属性,并且为属性的值指定数据类型。
class MyApp extends React.Component {
render() {
return(
{this.props.name} : {this.props.age} : {this.props.sex}
);
}
}
let p1 = {
name: '张三',
age: 18,
sex: '男'
};
ReactDOM.render(
//
,
document.getElementById('root')
);
React 的核心思想是组件化的思想,应用由组件搭建而成,而组件中最重要的概念是State(状态),State是一个组件的UI数据模型,是组件渲染时的数据依据。
定义一个合适的State,是正确创建组件的第一步。
State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来;
同时,State还必须是代表一个组件UI呈现的最小状态集,即State中的所有状态都是用于反映组件UI的变化,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态。
组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:
1. 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
2. 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
3. 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
4. 这个变量是否在组件的render方法中使用?如果**不是**,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性。并不是组件中用到的所有变量都是组件的状态!
class LikeButton extends React.Component {
//声明一个状态liked 使用this.state.liked获取状态的值
constructor(props) {
super(props)
this.state={liked: false};
}
handleClick(event) {
this.setState({liked: !this.state.liked});
}
render() {
return (
)
}
}
ReactDOM.render(
,
document.getElementById('root')
)
注意:**React在ES6的实现中,规定state在constructor中实现**
正确定义State***的方式如下:
(1)在constructor中实现state
(2)在constructor中通过bind绑定事件函数(事件函数是用来改变状态)
(3)在事件函数内部使用setState函数更改状态
(4)在组件中的render函数中使用该状态
(5)在组件上需要设置监听事件,去触发事件函数的执行
//定义组件
class LikeButton extends React.Component {
//constructor表示构造器,在constructor需要声明状态state,在声明state之前需要使用super(props);
constructor(props) {
super(props);//使用父类的属性
//声明状态
this.state = {
liked: false
}
//Currently, you are calling bind.
//But bind returns a bound function.
//You need to set the function to its bound value.
//目前,你正在调用绑定。但是绑定返回绑定函数。您需要将函数设置为其绑定值。
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({liked: !this.state.liked});
}
render() {
return (
)
}
}
ReactDOM.render(
,
document.getElementById('root')
)
(1)语法:
setState(object nextState[, function callback])
(2)说明:
- setState是React事件处理函数中和回调函数中触发UI更新的主要方法。
- 不能在组件内部通过this.state修改状态,因为该状态会在调用setState()后被替换。
- setState()不一定是同步的,为了性能提升,React会批量执行state和DOM渲染。
- setState()总是会触发一次组件重绘,但可在shouldComponentUpdate()中实现一些条件渲染逻辑来解决。setState默认是异步的,但有时候也是同步的
在计时器 和 原生Dom函数中,setState是一个同步函数,其它情况全是异步函数
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
clickCount: 0
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({clickCount: this.state.clickCount + 1});
}
render() {
return (
点击后次数变更: {this.state.clickCount}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
同步设置多个状态时(不常用),可以在setState函数的**第二个参数可以传递一个function回调函数,如下:
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
clickCount: 0,
isRed: false,
smallFont: true
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState(
{clickCount: this.state.clickCount + 1},
function() {
this.setState(
{isRed: !this.state.isRed},
function() {
this.setState({smallFont: !this.state.smallFont});
}
);
}
);
console.log(this.state.isred);
}
render() {
var redStyle = {color: 'red', fontSize: 50};
var blueStyle = {color: 'blue', fontSize: 14};
return (
点击后次数变更: {this.state.clickCount}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
状态上移:
当存在多个组件共同依赖一个状态,或是当子组件的props 数据需要被修改时,将这个状态放到对应组件的父组件中:
//子组件
class Site extends React.Component {
render() {
return (
{this.props.myData}
);
}
}
//父组件
class Content extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'hello'
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: '你好'});
}
render() {
return(
);
}
}
除了State, 组件的Props也是和组件的UI有关的。他们之间的主要区别是:
props 中的数据都是外界传递过来的
state 中的数据都是组件私有的;(通过Ajax 获取回来的数据,一般都是私有数据)
props 中的数据都是只读的,不能重新赋值
state 中的数据都是可读可写的
State定义在constructor内部,在super(props)代码后面;Props默认值定义在类(组件)的外部
当子组件的属性值是可变值时,采用状态上移:
状态上移通过属性将父组件的状态传递到子组件,那么父组件的状态发生变化时,子组件的属性也会改变
(自己实现反向传值,Vue中已经实现好了)
子组件获取父组件整个组件进行传参
父组件在调用子组件时,传入一整个组件给子组件
父组件中定义一个方法getChildrenMsg(resulet, msg),用来获取子组件传来的值以及执行其他操作
子组件在通过this.props来获取到一整个组件this.props.parent 或者this.props[parent]
子组件调用父组件步骤2里定义的方法进行传值this.props.parent.getChildrenMsg(this,val)
Parent:
import Children from './Children'
export default class Parent extends Component {
constructor(props) {
super(props)
this.state = {
msg: '父组件传值给子组件',
childrenMsg: ''
}
}
getChildrenMsg = (result, msg) => {
// console.log(result, msg)
this.setState({
childrenMsg: msg
})
}
render() {
return (
我是父组件
子组件传来的值为:{ this.state.childrenMsg }
{/* */}
)
}
}
Children:
export default class Children extends Component {
constructor(props) {
super(props)
this.state = {
msg: '子组件传值给父组件'
}
}
toParent = () => {
// console.log(this.props.parent.getChildrenMsg.bind(this, this.state.msg))
this.props.parent.getChildrenMsg(this, this.state.msg)
}
render() {
return (
{ 我是子组件 }
)
}
}