0

I have a button in React that executes a function onClick. I want to get rid of the button, and instead programmatically execute the function if window width < 1000px.

A restriction is that I can not add a plugin.

Here's what the code looks like...

// Do I need useState, useEffect?
import React, { PureComponent } from "react";

class MainNav extends PureComponent {
state = {
  // Does something go here? What goes here and how do I use
  // state to execute the function?
  navIsCollapsed: false,
};

// this controls rendering of huge images
toggleShowImages() {
  this.setState({
    navIsCollapsed: !this.state.navIsCollapsed,
  });
}

// I want this to be executed by width < 1000
handleSideNavToggle = () => {
  this.toggleShowImages(); // controls if React renders components
  document.body.classList.toggle("side-nav-closed");
}

Here's render the button that's currently executing the function. I want width < 1000 to programmatically execute its function.

// window width < 1000 should execute this function
<div onClick={this.handleSideNavToggle}>Don't render huge images</div>

// here are the images the function conditionally renders
<should show images && 
  <div>Massive huge image</div>
  <div>Massive huge image</div>
  <div>Massive huge image</div>
>

I could use CSS media query to show or hide the massive images I don't want, but that's horrible use of React.

I've looked and tried to implement similar questions on SO that either invoke plugins, are out of date, or the use case is too different (for example, "re-render everything based on screen size"). I've also tried to React-ify vanilla javascript. This seems like it ought to be simple to do but I can't make it work.

Any React wizards out there who can answer with a clean, efficient solution?

Deborah
  • 4,316
  • 8
  • 31
  • 45

2 Answers2

6

Use the above method that Mathis Delaunay mentioned to get viewport/window width, then to get rid of that button. Just simply add a condition to whether render it or not and then watch on state changes to trigger the function. Here I use hooks to do it

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

function App() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, [width]);

  useEffect(() => {
    width < 600 && handleSideNavToggle();
  },[width]);

  function handleSideNavToggle() {
    console.log("toggle it");
  }

  return (
    <div className="App">
      {width > 600 && (
        <button onClick={() => handleSideNavToggle()}>
          Don't render huge images
        </button>
      )}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Here is a working example. I set the width to be handled as 600 to make it easy to see.

https://codesandbox.io/s/react-hooks-counter-demo-w9wgv

Winchester
  • 460
  • 6
  • 19
  • I don't want the button ever in the DOM at all. I want to replace the button with width < 1000 to render the function. – Deborah Jul 14 '19 at 18:31
  • ok, then just hide that button when width < 1000, then use componenDidUpdate to watch on the width changes, if width < 1000, then execute the function you want. – Winchester Jul 15 '19 at 10:43
  • I am not trying to hide the button. I want the React function to replace the button and execute the script when screen width < 1000. I want to delete the button entirely. – Deborah Jul 15 '19 at 16:49
  • Maybe you should read more about React.https://reactjs.org/docs/conditional-rendering.html . By doing this, {this.state.width > 1000 &&
    Execute my function
    }, The button will be rendered to the DOM only this.state.width > 1000 . And by using componenDidUpdate, you can trigger the function when width < 1000.
    – Winchester Jul 15 '19 at 19:37
  • 1
    Ok, let me clarify your question, when window width < 1000, you want to remove the button and trigger this.handleSideNavToggle function automatically without have to be clicked? is that correct? – Winchester Jul 15 '19 at 20:32
  • Thank you, that was great! I've accepted the answer. I'm updating my description to match your solution, so future users don't get confused. – Deborah Jul 16 '19 at 04:20
  • Why this line is needed? `return () => window.removeEventListener("resize", handleResize);` – DaWe Oct 15 '21 at 18:50
  • 1
    @DaWe https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup – Winchester Oct 18 '21 at 07:26
0

Try looking at this answer, i think it is what your are searching for :

Get viewport/window height in ReactJS

You just need to check in the updateWindowDimension if the window.innerWidth is under 1000, if so, change the css button property to display : none; or visibility: hidden;.

Mathis Delaunay
  • 172
  • 1
  • 16
  • I've tried to implement that but although it delivers the width to the state, I'm too new to React to see where and how to call my function, and also everywhere I saw this answer it looked like the bind method was out of date. I need an answer with all the pieces. – Deborah Jul 14 '19 at 08:29