React.js

一起学React--组件定义和组件通讯

2019-03-31  本文已影响11人  一本正经的反派

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 变化时会触发更新。 会依次执行下面的生命周期

  1. static getDerivedStateFromProps()
  2. shouldComponentUpdate() // 必要时来做性能优化,在第一期提过
  3. render() // 必须要用
  4. getSnapshotBeforeUpdate()
  5. 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);
    });
  };
上一篇 下一篇

猜你喜欢

热点阅读