React主打函数式编程,配合上JSX语法,基本上可以把每个模块都封装为单独组件,用组件一时爽,一直用一直爽。
1.函数式组件
在React中最简单的即是创建一个函数式,没有生命周期的组件,这与 Vue 的单文件 .vue 一个完整生命周期组件不同,举个例子。
// 定义weblcome 组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
这里的props属性对象是React中组件单向数据传递的唯一标示,在函数式组件中,我们可以通过 props.name 来获取 其他组件传递的name 属性,这点和Vue是没有本质区别的。
// 子组件 获取name属性
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 父组件传入name属性
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
2.class 组件
函数式组件由于没有生命周期的定义,虽然简洁,但是拓展方面较差,我们把上面的welcome,改写为class组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
welcome继承自React.Component 组基类,在class组件中,作用域为当前组件,所以使用this对象来代替。
class组件有完整的生命周期,当组件插入到DOM中时,会依次调用生命周期函数。
render() 是class组件中必须实现的方法
当每次render 被触发是都会检查 this.props 和this.state 的变化、
同理适用于任何class 组件的检查方式
所以在处理函数时,要考虑好应该在组件生命周期的那一步触发,反之容易凉凉,或影响性能
3.顺滑的组件抽取方式
每个class组件, 无论单独调用,还是循环调用,都有自己的生命周期和单独的state。
举个实际场景。
比如:维护一个列表,列表中有, 全部,完成,失败,进行中,等状态type。
首先想到的是维护一个type 数组,然后通过map 循环的方式来产生列表
好处是数据操作方便,缺点就是和其他 n个列表公用一个state ,没有办法将其中某个item的状态区分开来
通过维护一个item组件,每个item都有自己的state,随心所欲的操作
all in all 每个通过map 循环的item, 都可以根据业务考虑封装为一个组件,因为你定义的时候就是一个变量, 不会像vue 通过v-for 指令渲染,后期抽离的成本不是很大。
<u>Warning</u> 如果shouldComponentUpdate 返回false 则不会render
当组件的props 或者state 变化时会触发更新。 会依次执行下面的生命周期
- static getDerivedStateFromProps()
- shouldComponentUpdate() // 必要时来做性能优化,在第一期提过
- render() // 必须要用
- getSnapshotBeforeUpdate()
- componentDidUpdate() // 最常用的组件状态更新判断
最比较常用的除了 componentDidMount() 之外,还有 componentDidUpdate() 来判断组件是否需要更新。
4.使用propTypes进行类型检查
propsTypes 是React友好的类型检查,通常和组件搭配使用。
使用方法非常简单,上图
二、 组件通讯方式
在单向通信中,最常见的就是通过prop方式。
父 - 子
子组件定义好item参数
父组件按照propTyes进行传参
子组件通过 this.props.item 取值
子 - 父
// 子组件
HomeItem.defaultProps = {
item: {},
// 定义回调函数
fetchData: () => {},
};
HomeItem.propTypes = {
item: PropTypes.object,
fetchData: PropTypes.func,
};
// 在子组件
handleSuccessDel = () => {
const successUrl = {
url: `/xq/statuses/destroy/${this.state.uid}.json`,
params: {},
};
const draftUrl = {
url: '/xq/statuses/draft/delete.json',
params: { id: this.props.item.textId },
};
const delUrl = this.props.item.typeName === '草稿' ? draftUrl : successUrl;
httpClient.post(delUrl.url, delUrl.params).then((res) => {
if (res.success) {
this.setState({
showModal: false,
});
Toast({ text: '删除成功', type: 'success' });
// 通过参数执行父组件传过来的callback 进而引起父组件状态改变
this.props.fetchData();
}
}).catch((err) => {
console.error(err);
});
};
网友评论