0%

vue3常用函数的使用

  • setup 函数用法,可以代替Vue2中的data和method属性,直接把逻辑加在setup中

  • ref 函数在temlate中用的变量需要用ref包装下

  • return出去的数组和方法在模板中才可以使用

  • reactive函数的用法,他的参数不是基本类型,而是一个object,这样就你不用在方法中写.value了,同时放回data就可以

    但是这样写,必须在template使用变量和方法的时候需要加上data.,这样显然是不符合我们开发的编码习惯的,
    我们可以想到在return的时候将data解构使用...拓展运算符,但是这样解构后就成了普通变量,不再具有响应式的能力,
    所以我们需要使用toRefs()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>{{loginName }}</div>
<div>{{userName}}</div>
<div>{{password}}</div>
</template>
<script>
import {reactive,ref,toRefs} from "vue"
export default {
name: "Home",
setup() {
const fromData = reactive({
userName:'admin',
password:'123456'
})
const loginName = ref("admin");
const data = toRefs(fromData);
return {
...data,
loginName
}
}
};
</script>

如何选择ref和reactive,两种方法都可以,他们都可以生成响应式对象,个人选择reactive

Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

创建3.0项目

通过脚手架vite安装

1
npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3

Vite目前仅支持 Vue 3.x以上,这意味着你不能使用不兼容Vue 3的组件库

目前基于Vue的第三方组件库兼容Vue 3的情况:

Ant Design Vue:支持 Vue 3.0 的 2.0.0 测试版已发布

ElementUI:尚未支持

MintUI:尚未支持

iView(ViewUI):尚未支持

Vue2-leaflet:很明显不支持

通过脚手架vue-cli安装

首先全局更新最新版的 Vue CLI,4.5.0以上版本支持 Vue3:

1
2
npm install -g @vue/cli # OR yarn global add @vue/cli
vue create hello-vue3

Vue3.0 的设计目标

  • 更小

  • 更快

  • 加强 TypeScript 支持

  • 加强 API 设计一致性

  • 提高自身可维护性

  • 开放更多底层功能

压缩包体积更小

当前最小化并被压缩的 Vue 运行时大小约为 20kB(2.6.10 版为 22.8kB)。Vue 3.0 捆绑包的大小大约会减少一半,即只有 10kB!

Object.defineProperty —> Proxy

Object.defineProperty 是一个相对比较昂贵的操作,因为它直接操作对象的属性,颗粒度比较小。将它替换为 es6 的 Proxy,在目标对象之上架了一层拦截,代理的是对象而不是对象的属性。这样可以将原本对对象属性的操作变为对整个对象的操作,颗粒度变大。

javascript 引擎在解析的时候希望对象的结构越稳定越好,如果对象一直在变,可优化性降低,proxy 不需要对原始对象做太多操作。

virtual DOM 重构

vdom 的本质是一个抽象层,用 javascript 描述界面渲染成什么样子。react 用 jsx,没办法检测出可以优化的动态代码,所以做时间分片,vue 中足够快的话可以不用时间分片。

vue 的特点是底层为 Virtual DOM,上层包含有大量静态信息的模版。为了兼容手写 render function,最大化利用模版静态信息,vue3.0 采用了动静结合的解决方案,将 vdom 的操作颗粒度变小,每次触发更新不再以组件为单位进行遍历,主要更改如下

  • 将模版基于动态节点指令切割为嵌套的区块
  • 每个区块内部的节点结构是固定的
  • 每个区块只需要以一个 Array 追踪自身包含的动态节点

vue3.0 将 vdom 更新性能由与模版整体大小相关提升为与动态内容的数量相关

Vue 3 中需要关注的一些新功能包括:

  • 组合式 API
  • Teleport
  • 片段
  • 触发组件选项
  • createRenderer API 来自@vue/runtime-core 创建自定义渲染器
  • 单文件组件组合式 API 语法糖
  • 单文件组件状态驱动的 css 变量
  • 单文件组件style scoped现在可以包含全局规则或只针对插槽内容的规则

安装axios

Axios的安装可以使用npm来进行安装,你可以直接在项目根目录下,输入下面的代码。

npm install -save axios

安装好axiso之后,需要在使用ajax的地方先引入axios

1
import axios from 'axios'

引入后,可以在componentDidMount生命周期函数里请求ajax,我也建议在componentDidMount函数里执行,因为在render里执行,会出现很多问题,比如一直循环渲染;在componentWillMount里执行,在使用RN时,又会有冲突。所以强烈建议在componentDidMount函数里作ajax请求。

1
2
3
4
5
componentDidMount(){
axios.post('https:...')
.then((res)=>{console.log('axios 获取数据成功:'+JSON.stringify(res)) })
.catch((error)=>{console.log('axios 获取数据失败'+error)})
}

首先你要确认你安装了React Developer Tools 有了这个浏览器插件,就可以在控制台中找到React标签,然后在右边点开设置,选中highlight Updates

![image-20200628160640699](/Users/zhaohui/Library/Application Support/typora-user-images/image-20200628160640699.png)

这时候你在浏览器的文本框中输入一下内容,你可以清楚的看到子组件也发生了重新render的情况。

有很多程序员会忽略这样的性能损耗,认为没有什么大不了的,但是软件的卡顿是一点点产生的,所以必须要减少性能损耗。

这时我们可以用shouldComponentUpdate解决

这个问题看似很小,但是当你页面很复杂时,足以影响用户体验。其实用shouldComponentUpdate函数就可以简单的解决调这个问题。

![image-20200628161020272](/Users/zhaohui/Library/Application Support/typora-user-images/image-20200628161020272.png)

现在的代码就优雅一些了,也不那么暴力了。这就算是完美解决了子组件的渲染性能问题,你写的代码质量也得到了提高。

React声明周期的四个大阶段:

  1. Initialization:初始化阶段。
  2. Mounting: 挂在阶段。
  3. Updation: 更新阶段。
  4. Unmounting: 销毁阶段

因此可以把React的生命周期分为两类:挂载卸载过程和更新过程。
React的生命周期图:

WechatIMG108

挂载卸载过程

constructor()

constructor()中完成了React数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。
注意:只要使用了constructor()就必须写super(),否则会导致this指向错误。

componentWillMount()

componentWillMount()一般用的比较少,它更多的是在服务端渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。

componentDidMount()

组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

componentWillUnmount ()

在此处完成组件的卸载和数据的销毁。

  1. clear你在组建中所有的setTimeout,setInterval
  2. 移除所有组建中的监听 removeEventListener
  3. 有时候我们会碰到这个warning:
1
Can only update a mounted or mounting component. This usually      means you called setState() on an unmounted component. This is a   no-op. Please check the code for the undefined component.

原因:因为你在组件中的ajax请求返回setState,而你组件销毁的时候,请求还未完成,因此会报warning
解决方法:

1
2
3
4
5
6
7
8
9
10
11
componentDidMount() {
this.isMount === true
axios.post().then((res) => {
this.isMount && this.setState({ // 增加条件ismount为true时
aaa:res
})
})
}
componentWillUnmount() {
this.isMount === false
}

更新过程

componentWillReceiveProps (nextProps)

  1. 在接受父组件改变后的props需要重新渲染组件时用到的比较多
  2. 接受一个参数nextProps
  3. 通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件
1
2
3
4
5
6
7
8
  componentWillReceiveProps (nextProps) {
nextProps.openNotice !== this.props.openNotice&&this.setState({
openNotice:nextProps.openNotice
},() => {
console.log(this.state.openNotice:nextProps)
//将state更新为nextProps,在setState的第二个参数(回调)可以打 印出新的state
})
}

shouldComponentUpdate(nextProps,nextState)

  1. 主要用于性能优化(部分更新)
  2. 唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
  3. 因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断

componentWillUpdate (nextProps,nextState)

shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。

componentDidUpdate(prevProps,prevState)

组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。

render()

render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

![image-20200601173445152](/Users/zhaohui/Library/Application Support/typora-user-images/image-20200601173445152.png)

getDerivedStateFromProps(nextProps, prevState)

代替componentWillReceiveProps()。
老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// before
componentWillReceiveProps(nextProps) {
if (nextProps.isLogin !== this.props.isLogin) {
this.setState({
isLogin: nextProps.isLogin,
});
}
if (nextProps.isLogin) {
this.handleClose();
}
}

// after
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.isLogin !== prevState.isLogin) {
return {
isLogin: nextProps.isLogin,
};
}
return null;
}

componentDidUpdate(prevProps, prevState) {
if (!prevState.isLogin && this.props.isLogin) {
this.handleClose();
}
}

这两者最大的不同就是:
在 componentWillReceiveProps 中,我们一般会做以下两件事,一是根据 props 来更新 state,二是触发一些回调,如动画或页面跳转等。

  1. 在老版本的 React 中,这两件事我们都需要在 componentWillReceiveProps 中去做。
  2. 而在新版本中,官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更为清晰。而且在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。

getSnapshotBeforeUpdate(prevProps, prevState)

代替componentWillUpdate。
常见的 componentWillUpdate 的用例是在组件更新前,读取当前某个 DOM 元素的状态,并在 componentDidUpdate 中进行相应的处理。
这两者的区别在于:

  1. 在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在
    componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。
  2. getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。
    此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

在react典型的数据流中,props传递是父子组件交互的唯一方式;通过传递一个新的props值来使子组件重新re-render,从而达到父子组件通信。当然,就像react官网所描述的一样,在react典型的数据量之外,某些情况下(例如和第三方的dom库整合,或者某个dom元素focus等)为了修改子组件我们可能需要另一种方式,这就是ref方式。

ref简介

React提供的这个ref属性,表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例;需要区分一下,ReactDOM.render()渲染组件时返回的是组件实例;而渲染dom元素时,返回是具体的dom节点。

ref可以挂到任何组件上,可以挂到组件上也可以是dom元素上;

挂到组件(这里组件指的是有状态组件)上的ref表示对组件实例的引用,而挂载到dom元素上时表示具体的dom元素节点。

ref可以设置回调函数

ref属性可以设置为一个回调函数,这也是官方强烈推荐的用法;这个函数执行的时机为:

  • 组件被挂载后,回调函数被立即执行,回调函数的参数为该组件的具体实例。
  • 组件被卸载或者原有的ref属性本身发生变化时,回调也会被立即执行,此时回调函数参数为null,以确保内存泄露。

例如下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RegisterStepTwo = React.createClass({
getInitialState(){
return {visible: true};
},
changeVisible(){
this.setState({visible: !this.state.visible});
},
refCb(instance){
console.log(instance);
},
render(){
return(
<div>
<button type="button" onClick={this.changeVisible}>{this.state.visible ? '卸载' : '挂载'}ConfirmPass
</button>
{
this.state.visible ?
<ConfirmPass ref={this.refCb} onChange={this.handleChange}/>: null
}
</div>
)
}
});

上述代码,渲染到页面时可以发现console.log出对应的组件实例,切换按钮时,ConfirmPass也在挂载与卸载之间切换,所以能看到不同的console.log结果。

ref可以设置字符串

ref还可以设置为字符串值,而不是回调函数;这种方式基本不推荐使用,或者在未来的react版本中不会再支持该方式,但是可以了解一下。

例如下面input设置ref的值为字符串。

1
<input ref="input" />

然后在其他地方如事件回调中通过this.refs.input可以访问到该组件实例,其实就是dom元素节点。

1
2
let inputEl = this.refs.input;
//然后通过inputEl来完成后续的逻辑,如focus、获取其值等等

获取ref引用组件对应的dom节点

不管ref设置值是回调函数还是字符串,都可以通过ReactDOM.findDOMNode(ref)来获取组件挂载后真正的dom节点。

但是对于html元素使用ref的情况,ref本身引用的就是该元素的实际dom节点,无需使用ReactDOM.findDOMNode(ref)来获取,该方法常用于React组件上的ref。

ref在有状态组件中的使用

上文说到过ref用到react有状态组件时,ref引用的是组件的实例;所以可以通过子组件的ref可以访问到子组件实例的propsstaterefs、实例方法(非继承而来的方法)等等。

ref在无状态组件中的使用

无法通过ref来获取无状态组件实例。

另外,对于无状态组件我们想访问的无非是其中包含的组件或者dom元素,我们可以通过一个变量来保存我们想要的组件或者dom元素组件的实例引用。例如下面代码:

copy

1
2
3
4
5
6
7
8
function TestComp(props){
let refDom;
return (<div>
<div ref={(node) => refDom = node}>
...
</div>
</div>)
}

这样,可以通过变量refDom来访问到无状态组件中的指定dom元素了,访问其中的其他组件实例类似。

ref在HOC中存在问题

react的HOC是高阶组件,简单理解就是包装了一个低阶的组件,最后返回一个高阶的组件;高阶组件其实是在低阶组件基础上做了一些事情,比方说antd组件的Form create的方法,它就是在为低阶组件封装了一些特殊的属性,比如form属性。

既然HOC会基于低阶组件生成一个新的高阶组件,若用ref就不能访问到我们真正需要的低阶组件实例,我们访问到的其实是高阶组件实例。所以:

若HOC不做特殊处理,ref是无法访问到低阶组件实例的

要想用ref访问低阶组件实例,就必须得HOC支持,就像Redux的connect方法提供的withRef属性来访问低阶组件一样。具体可以参考这里

总结

ref提供了一种对于react标准的数据流不太适用的情况下组件间交互的方式,例如管理dom元素focus、text selection以及与第三方的dom库整合等等。 但是在大多数情况下应该使用react响应数据流那种方式,不要过度使用ref。

另外,在使用ref时,不用担心会导致内存泄露的问题,react会自动帮你管理好,在组件卸载时ref值也会被销毁。

最后补充一点:

不要在组件的render方法中访问ref引用,render方法只是返回一个虚拟dom,这时组件不一定挂载到dom中或者render返回的虚拟dom不一定会更新到dom中。

React中的类型检查:prop-types 包

1
import PropTypes from 'prop-types';

编写组件

1
2
3
4
5
6
7
8
9
10
11
12
13
import PropTypes from 'prop-types';

class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}

Greeting.propTypes = {
name: PropTypes.string
};

PropTypes 提供一系列验证器,可用于确保组件接收到的数据类型是有效的。在本例中, 我们使用了 PropTypes.string。当传入的 prop 值类型不正确时,JavaScript 控制台将会显示警告。出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

propTypes提供了使用不同验证器的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import PropTypes from 'prop-types';

MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,

// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,

// 一个 React 元素。
optionalElement: PropTypes.element,

// 一个 React 元素类型(即,MyComponent)。
optionalElementType: PropTypes.elementType,

// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),

// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),

// 一个对象可以是几种类型中的任意一个类型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),

// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),

// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),

// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),

// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,

// 任意类型的数据
requiredAny: PropTypes.any.isRequired,

// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},

// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};

限制单个元素

可以通过PropsTypes.element来确保传递组件的children中只包含一个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import PropTypes from 'prop-types';

class MyComponent extends React.Component {
render() {
// 这必须只有一个元素,否则控制台会打印警告。
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}

MyComponent.propTypes = {
children: PropTypes.element.isRequired
};

默认prop值

您可以通过配置特定的 defaultProps 属性来定义 props 的默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}

// 指定 props 的默认值:
Greeting.defaultProps = {
name: 'Stranger'
};

// 渲染出 "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);

如果你正在使用像 transform-class-properties 的 Babel 转换工具,你也可以在 React 组件类中声明 defaultProps 作为静态属性。此语法提案还没有最终确定,需要进行编译后才能在浏览器中运行。要了解更多信息,请查阅 class fields proposal

1
2
3
4
5
6
7
8
9
10
11
class Greeting extends React.Component {
static defaultProps = {
name: 'stranger'
}

render() {
return (
<div>Hello, {this.props.name}</div>
)
}
}

defaultProps 用于确保 this.props.name 在父组件没有指定其值时,有一个默认值。propTypes 类型检查发生在 defaultProps 赋值后,所以类型检查也适用于 defaultProps

我们经常使用console.log这种很二的形式来调试程序。其实React在浏览器端是有一个调试工具的,这就是React developer tools,这个是React人必下的一个调试工具。这节课就主要学习一下React developer tools的下载和简单使用。

下载React developer tools

这个需要在chrome浏览器里进行,并且需要科学上网(自行百度)。

  1. 点击浏览器地址栏最右边的...,然后选择更多工具,然后选择扩展程序
  2. 点击打开chrome网上应用店,直接在搜索框里搜索React,出现的第一个就是。
  3. 点击添加至Chrome,然后就是等待了……….

这段内容推荐看视频吧,其实并不复杂,但是都是需要上图的,我又懒得作图。

React developer tools 的三种状态

React developer tools有三种颜色,三种颜色代表三种状态:

  1. 灰色: 这种就是不可以使用,说明页面不是又React编写的。
  2. 黑色: 说明页面是用React编写的,并且处于生成环境当中。
  3. 红色: 说明页面是用React编写的,并且处于调试环境当中。

React developer tools 的使用

打开浏览器,然后按F12,打开开发者工具,然后在面板的最后一个,你会返现一个React,这个就是安装的插件了。

在这里你可以清晰的看到React的结构,让自己写的代码更加清晰,你还可以看到组间距的数据传递,再也不用写console.log来测试程序了。

总结 : 这节课我们学习了React调试工具的安装和使用,在工作中一个前端的调试都是在这里进行的

React 单项数据流

React是单项数据流,数据流主要从父节点传递到子节点(通过props)

如果顶层(父级)的某个props改变了,React会重渲染所有的子节点

Props:

props是property的缩写,可以理解为HTML标签的attribute。

  不可以使用this.props直接修改props,因为props是只读的,props是用于整个组件树中传递数据和配置。

  在当前组件访问props,使用this.props

State:

​ 每个组件都有属于自己的statestateprops的区别在于前者(state)只存在于组件内部,只能从当前组件调用this.setState修改state值(不可以直接修改this.state!)。

  一般我们更新子组件都是通过改变state值,将state值通过属性传递给子组件,子组件的获取props值从而达到更新。

函数式编程

  1. 函数式编程让我们的代码更清晰,每个功能都是一个函数。
  2. 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试。

父组件向子组件传值

这里只介绍最实用的,最快速的上手方法。就是使用组件属性的形式父组件给子组件传值。比如:我们在<sunshineItem>组件中加入content属性,然后给属性传递{item},这样就完成了父组件向子组件传值。

1
<sunshineItem content={item}/>

现在值已经顺利的传递了过去,这时候可以通过this.props.xxx的形式进行接受,比如传递过来的值,可以用如下代码进行接收。

1
2
3
4
5
6
7
8
9
10
11
import React, { Component } from 'react'; //imrc
class sunshineItem extends Component { //cc

render() {
return (
<div>{this.props.content}</div>
);
}
}

export default sunshineItem;

子组件向父组件传递数据

现在要作这样一个功能:点击组件中的菜单项后,删除改菜单项。在前边的课程中已经学习了这个知识,知识现在组件拆分了,就涉及了一个字组件向父组件传递数据的知识需要掌握。

先来绑定点击事件,这时候当然是要在组件中绑定了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { Component } from 'react'; //imrc
class sunshineItem extends Component { //cc

render() {
return (
<div onClick={this.handleClick}>{this.props.content}</div>
);
}

handleClick(){
console.log('点击....')
}

}

export default sunshineItem;

React有明确规定,子组件时不能操作父组件里的数据的,所以需要借助一个父组件的方法,来修改父组件的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>
{
this.state.list.map((item,index)=>{
return (
<sunshineItem
key={index+item}
content={item}
index={index}
//关键代码-------------------start
deleteItem={this.deleteItem.bind(this)}
//关键代码-------------------end
/>
)
})
}
</ul>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from 'react'; //imrc
class sunshineItem extends Component { //cc
//--------------主要代码--------start
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}
//--------------主要代码--------end
render() {
return (
<div onClick={this.handleClick}>{this.props.content}</div>
);
}

handleClick(){
console.log('点击....',this.props.index)
this.props.deleteItem(this.props.index)
}

}

export default sunshineItem;