React组件「设计模式」快速指南

Github: github.com/gaoljie/rea…

函数组件(Functional Component)

函数组件是纯 UI 组件,也称作傻瓜组件, 或者无状态组件。渲染所需要的数据只通过 props 传入, 不需要用 class 的方式来创建 React 组件, 也不需要用到 this 关键字,或者用到 state

函数组件具有以下优点

  • 可读性好
  • 逻辑简单
  • 测试简单
  • 代码量少
  • 容易复用
  • 解耦
const Hello = props => 
Hello {props.name}
; const App = props => ; 复制代码

什么情况下不使用函数组件? 如果你需要用到 react 生命周期, 需要用到 state, 函数组件就没办法满足要求了。 但是新的 Hook 特性出来之后又大大提升了函数组件的应用范围, 所以没有最佳的设计模式,都是要因地制宜。

Render Props

给某个组件通过 props 传递一个函数,并且函数会返回一个 React 组件,这就是 render props.

const Hello = props => 
{props.render({ name: "World" })}
; const App = props =>

Hello {props.name}

} />; 复制代码

你也可以把函数放在组件 tag 的中间,组件可以通过props.children 获取

const Hello = props => 
{props.children({ name: "World" })}
; const App = props => {props =>

Hello {props.name}

}
; //复用 const App2 = props => {props =>

Hey {props.name}

}
; 复制代码

render props 提高了组件的复用性和灵活性, 相比组件直接渲染特定模板,通过 render props,父组件自定义需要的模板,子组件只要调用父组件提供的函数, 传入需要的数据就可以了。

高阶组件(HOC)

高阶组件是一个接受 Component 并返回新的 Component 的函数。之所以叫高阶组件是因为它和函数式编程中的高阶函数类似, 一个接受函数为参数, 或者返回值为函数的函数便称作高阶函数.

const Name = props => {props.children};

const reverse = Component => {
  return ({ children, ...props }) => (
    
      {children
        .split("")
        .reverse()
        .join("")}
    
  );
};

const ReversedName = reverse(Name);

const App = props => hello world;
复制代码

reverse 函数接受一个 Component 参数,返回一个可以 reverse 内容的新的函数式组件。这个高阶组件封装了 reverse 方法,以后每次需要 reverse 某些组件的内容就没必要重复写一下步骤:

const Name = props => {props.children};

const App = props => (
  
    {"hello world"
      .split("")
      .reverse()
      .join("")}
  
);
复制代码

组合组件(Compound Components)

组合组件设计模式一般应用在一些共享组件上。 如 ,不传任何props的情况下React可以直接用默认的组件,但是如果加了value 属性,如果不传onChange属性开始输入的话, input框不会有任何变化, 因为已经被父组件控制, 需要父组件指定一个方法, 告诉子组件value如何变化.

class App extends Component{
  state = {
    value: '',
  }

  onChange = (e) => {
    this.setState({value: e.target.value})
  }

  render() {
    return (
          <input value={this.state.value} onChange={this.onChange}/>
    );
  }
}
复制代码

下面是一个实际的例子, 如果给Counter组件传入count属性的话, Counter组件自己的addCount就不再起作用, 需要用户传入一个新的addCount方法来决定count如何变化.

class Counter extends Component{
  state = {
    count: 0
  }

  isControlled(prop) {
    return this.props[prop] !== undefined
  }

  getState() {
    return {
      count: this.isControlled('count') ? this.props.count : this.state.count,
    }
  }

  addCount = () => {
    if (this.isControlled('count')) {
      this.props.addCount()
    } else {
      this.setState(state => ({count: state.count + 1}))
    }
  }

  render() {
    return (
        <div>
          <p>You clicked {this.getState().count} timesp>
          <button onClick={() => this.addCount()}>
            Click me
          button>
        div>
    );
  }
}

class App extends Component{
  state = {
    count: 0,
  }

  addCount = () => {
    this.setState(state => ({count: state.count + 2}))
  }

  render() {
    return (
        <Fragment>
          {/*this counter add 1 every time*/}
          <Counter/>
          {/*this counter add 2 every time*/}
          <Counter count={this.state.count} addCount={this.addCount}/>
        Fragment>
    );
  }
}
复制代码

Hook

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数,用户可以在不使用class的情况下用一些 React 的特性,如state等等.

useState 就是一个 HookuseState 唯一的参数就是初始 state,通过在函数组件里调用它来给组件添加一些内部 state。React 会在重复渲染时保留这个 state。useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。

你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

useContext则可以传入Context对象,获取当前的context value. 当相应的Context.Provider更新value, useContext会触发rerender, 并传入最新的context value

import React, { useState, useEffect, useContext } from 'react';

const TitleContext = React.createContext({})
const TitleProvider = TitleContext.Provider

function Counter() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  useEffect(() => {
    // Update the document title using the browser API
    console.log(`You clicked ${count} times`)
  });

  const contextTitle = useContext(TitleContext)
  return (
      <div>
        <h1>{contextTitle}h1>
        <p>You clicked {count} timesp>
        <button onClick={() => setCount(count + 1)}>
          Click me
        button>
      div>
  );
}

const App = props => (
    <TitleProvider value={'Counter'}>
      <Counter/>
    TitleProvider>
)
复制代码

以下是React所有的hook:

  • Basic Hooks
    • useState
    • useEffect
    • useContext
  • Additional Hooks
    • useReducer
    • useCallback
    • useMemo
    • useRef
    • useImperativeHandle
    • useLayoutEffect
    • useDebugValue

参考:

medium.com/@soorajchan…

blog.logrocket.com/guide-to-re…

engineering.dollarshaveclub.com/reacts-stat…

zh-hans.reactjs.org/docs/hooks-…

medium.com/yazanaabed/…

你可能感兴趣的:(React组件「设计模式」快速指南)