在React中使用Browser API - panchaow/blog GitHub Wiki

在使用 React 时可能经常会遇到要使用Browser API。下面以使用窗口大小为例,总结几种可能会用到的 Pattern。

高阶组件 Higher-order component

能够接受一个函数作为参数或者返回一个函数的函数被称作高阶函数。而高阶组件在概念上和高阶函数非常类似,只不过高阶组件返回的是一个React Component。React Redux提供的connect函数实际上就是一个高阶组件(实际上是一个返回高阶组件的高阶函数)。如果使用得当,高阶组件可以帮助我们重用组件的逻辑,让我们写出非常优雅的代码。

创建一个高阶组件:

const getDisplayName = WrappedComponent =>
  WrappedComponent.displayName || WrappedComponent.name || "Component";

const withWindowSize = WrappedComponent => {
  class Comp extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        width: window.innerWidth,
        height: window.innerHeight
      };
      this.updateWindowSize = this.updateWindowSize.bind(this);
    }
    updateWindowSize() {
      this.setState({
        width: window.innerWidth,
        height: window.innerHeight
      });
    }
    componentDidMount() {
      window.addEventListener("resize", this.updateWindowSize);
    }
    componentWillUnmount() {
      window.removeEventListener("resize", this.updateWindowSize);
    }
    render() {
      return (
        <WrappedComponent width={this.state.width} height={this.state.height} />
      );
    }
  }
  Comp.displayName = `WithWindowSize(${getDisplayName(WrappedComponent)})`;
  return Comp;
};

使用高阶组件:

const App = withWindowSize(function({ width, height }) {
  return <div>{`width: ${width}, height: ${height}`}</div>;
});

Render Prop

Render Prop是通过一个值为函数的属性来重用代码,在 React Motion中被大量使用。如果使用Render Prop来实现,代码如下:

class WindowSize extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      width: window.innerWidth,
      height: window.innerHeight
    };
    this.updateWindowSize = this.updateWindowSize.bind(this);
  }
  updateWindowSize() {
    this.setState({
      width: window.innerHeight,
      height: window.innerHeight
    });
  }
  componentDidMount() {
    window.addEventListener("resize", this.updateWindowSize);
  }
  componentWillUnmount() {
    window.removeEventListener("resize", this.updateWindowSize);
  }
  render() {
    const render = this.props.render;
    return render({ width: this.state.width, height: this.state.height });
  }
}

const App = () => (
  <WindowSize
    render={({ width, height }) => {
      return <div>{`width: ${width}, height: ${height}`}</div>;
    }}
  />
);

React Hooks

React Hooks 可能是最近关于 React 的最热门的话题了。 React Hooks 是 React 在 v16.8 引入的新 API。以前的函数组件由于没有 state 和生命周期的支持,被称为 SFC (Stateless Functional Component),常用于实现 Presentat Component。 但是通过使用 React Hooks,函数组件中也可以使用 state 和生命周期。甚至,用户可以自定义 React Hooks,用于封装一些可以复用的代码。

const useWindowSize = () => {
  const [size, setSize] = React.useState({
    width: window.innerWidth,
    height: window.innerHeight,
  })

  React.useEffect(() => {
    const updateSize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      })
    };
    window.addEventListener("resize", updateSize);

    return () => {
      window.removeEventListener("resize", updateSize);
    };
  }, []);

  return size;
};

function App() {
  const { width, height } = useWindowSize();
  return <div>{`width: ${width}, height: ${height}`}</div>;
}
⚠️ **GitHub.com Fallback** ⚠️