[React log] First acquaintance with react-hooks

Preface

Now slightly larger sites will use H5/PC side parallel, through nignx to obtain the UA information of the browser to switch sites.

But this is difficult to achieve for some corporate sites or small projects with insufficient staff.

Realizing responsive layout through CSS media queries is the mainstream way.

However, sometimes in a React program, it is necessary to conditionally render different components according to the screen size (writing media queries is too troublesome, it is better to write another component), in fact, using React Hooks can be more flexible to achieve.

1. Option 1: innerWidth

A very simple and rough solution, which is known to all front-ends:

const MyComponent = () => {
    
    
  // 当前窗口宽度
  const width = window.innerWidth;
  // 邻介值
  const breakpoint = 620;
  // 宽度小于620时渲染手机组件,反之桌面组件
  return width < breakpoint ? <MobileComponent /> : <DesktopComponent />;
}

This simple solution will definitely work. According to the window width of the user device, we can present a desktop view or a mobile view.

However, when the window is resized, the update of the width value is not resolved, and the wrong component may be rendered.

2. Option 2: Hooks+resize

It is also simple to say, when the resize event is monitored, useEffect is triggered to change the data.

const MyComponent = () => {
    
    
  const [width, setWidth] = React.useState(window.innerWidth);
  const breakpoint = 620;

  React.useEffect(() => {
    
    
    window.addEventListener("resize", () => setWidth(window.innerWidth));
  }, []);

  return width < breakpoint ? <MobileComponent /> : <DesktopComponent />;
}

But you who are proficient in Hooks must know that there is a memory performance consumption problem here: the resize event has not been removed!

Optimized version:

const useViewport = () => {
    
    
  const [width, setWidth] = React.useState(window.innerWidth);

  React.useEffect(() => {
    
    
    const handleWindowResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handleWindowResize);
    return () => window.removeEventListener("resize", handleWindowResize);
  }, []);

  return {
    
     width };
}

3. Option 3: Build useViewport

Custom React Hooks can reuse components/functions to the greatest extent. Building one is also very simple:

const useViewport = () => {
    
    
  const [width, setWidth] = React.useState(window.innerWidth);

  React.useEffect(() => {
    
    
    const handleWindowResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handleWindowResize);
    return () => window.removeEventListener("resize", handleWindowResize);
  }, []);

  return {
    
     width };
}

Simplified component code:

const MyComponent = () => {
    
    
  const {
    
     width } = useViewport();
  const breakpoint = 620;

  return width < breakpoint ? <MobileComponent /> : <DesktopComponent />;
}

But there is another performance issue here:

Responsive layout affects multiple components. If useViewport is used in multiple places, it will waste performance.

At this time, you need another child of React: React Context (Context) to help.

4. The ultimate solution: Hooks+Context

We will create a new file viewportContext in which the state of the current viewport size and calculation logic can be stored.

const viewportContext = React.createContext({
    
    });

const ViewportProvider = ({
    
     children }) => {
    
    
  // 顺带监听下高度,备用
  const [width, setWidth] = React.useState(window.innerWidth);
  const [height, setHeight] = React.useState(window.innerHeight);

  const handleWindowResize = () => {
    
    
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  }

  React.useEffect(() => {
    
    
    window.addEventListener("resize", handleWindowResize);
    return () => window.removeEventListener("resize", handleWindowResize);
  }, []);

  return (
    <viewportContext.Provider value={
    
    {
    
     width, height }}>
      {
    
    children}
    </viewportContext.Provider>
  );
};

const useViewport = () => {
    
    
  const {
    
     width, height } = React.useContext(viewportContext);
  return {
    
     width, height };
}

Next, you need to be at the React root node to ensure that the App has been wrapped:

const App = () => {
    
    
  return (
    <ViewportProvider>
      <AppComponent />
    </ViewportProvider>
  );
}

In the future, every useViewport() is actually just sharing Hooks.

const MyComponent = () => {
    
    
  const {
    
     width } = useViewport();
  const breakpoint = 620;

  return width < breakpoint ? <MobileComponent /> : <DesktopComponent />;
}

Insert picture description here

Guess you like

Origin blog.csdn.net/u013034585/article/details/106327634
Recommended