React组件重构实践

基础应用

一个可以搜索、删除书籍的单页面:


image.png

基础代码以create react app生成,使用ES6的语法特征进行重构。

基础代码

整个页面不做任何组件拆分,只有一个BookListing组件:

const list=[
  {
    title: 'Road to React',
    url: 'https://facebook.github.io/react/',
    author: 'Jordan Walke',
    num_comments: 3,
    points: 4,
    objectID: 0,
  },
  ...
];

const isSearched = function(searchTerm){
  return function(item) {
    return item.title.toLowerCase().includes(searchTerm.toLowerCase());
  }
}
export default class BookListing extends Component {

  constructor(props) {
    super(props);
    this.state = {
      list,
      searchTerm: ''
    };

    this.search = this.search.bind(this);
    this.dismiss = this.dismiss.bind(this);
  }

  search(e) {
    this.setState({
      searchTerm: e.target.value
    });
  }

  dismiss(objectID) {
    let updatedList = this.state.list.filter(item => item.objectID !== objectID);
    this.setState({
      list: updatedList
    });
  }

  render() {
    return (
      
Search this.search(e)} >
{this.state.list.filter(isSearched(this.state.searchTerm)) .map(item =>
{item.title} {item.author} {item.num_comments} {item.points}
)}
) } }

重构实践

  • ES6箭头函数

isSearched函数可以使用ES6的箭头函数语法进行重构,改写后:

const isSearched = searchTerm => item => item.title.toLowerCase().includes(searchTerm.toLowerCase())

仅用一行就可以完成同样的功能。

  • 解构

ES6支持对象解构,render函数中的state可以解构,简化链式调用的长度:

render() {
  const {list, searchTerm} = this.state;
  // ...
  {list.filter(isSearched(searchTerm))
    .map(item => 
      
{/* ... */}
)} }
  • 组件拆分

BookListing组件过于复杂,可以拆分成几个职责更单一的组件,提取Search,Table组件,对应于搜索框和列表:

export default class Search extends Component {
  render() {
    const {value, search, children} = this.props;
    return (
      
Search
) } }
export default class Table extends Component {
  render() {
    const { list, pattern, onDismiss } = this.props;
    return (
      
{list.filter(isSearched(searchTerm)) .map(item =>
{item.title} {item.author} {item.num_comments} {item.points}
)}
) } }

改写顶层组件如下:

export default class extends Component {
  //...

  render() {
    
} }

button也可以抽取成为单独的组件:

export default class Button extends Component {
  render() {
    return(
      
    )
  }
}
  • 使用children属性

React组件的props提供了children属性,代表组件的子元素,可以对Search,Button组件使用:


  Search

// use children
export default class Search extends Component {
  render() {
    const {value, onChange, children} = this.props;
    return (
      
{children} } }
  • 引入无状态组件

以上提取的3个组件,基本都不需要维护自身状态,可以改写为无状态组件:

export default function Search(props) {
  const { value, onChange, children } = props;
  return (
    
{children} ) }

另外两个组件也可以做同样的处理。无状态组件除了语法简洁、便于测试等优点外,无状态的特性使得它没有React组件的生命周期管理,因此在渲染时相比于React组件有更好的性能。

  • 更纯的函数式组件

props可以通过解构直接当做函数参数,然后直接加上箭头函数进行改造,省掉函数内部的props参数解析,并且直接去掉return关键字:

export default ({ value, onChange, children }) =>
  
{children}

以上处理也同样适用于另外两个提取的组件。

你可能感兴趣的:(React组件重构实践)