0

I'm working with Docusaurus, which provides a siteConfig.js as a config props. As such, I have to use this props to build my site components. Working code is formatted like this:

const React = require("react");

class SamplePage extends React.Component {
  render() {
    const siteConfig = this.props.config;
    return <div>{siteConfig.title}</div>;
  }
}

module.exports = SamplePage;

I have another segment of working code shown in this question, but it uses a different set-up where const {useState} = React; is used in place of const React = require("react"); and <div id="root"> with ReactDOM.render(<SamplePage/>, document.getElementById("root")); in place of module.exports = SamplePage;. I understand this allows running code snippets on SE, but it doesn't show me how the imports and exports are supposed to function in the context of this Docusaurus project. What I want to do is incorporate the code segment into the React.Component or otherwise construct this component to employ theuseState hook with the config props in order to assert or deny the isOpen attribute of 3 detail tags, using 2 button(s) to control the hook:

const {useState} = React;

const SamplePage = () => {
    const [isOpen, setIsOpen] = React.useState(false); 

    return (
        <div>
            <details open={isOpen}>
                <summary>
                    First text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Second text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Third text detail.
                </summary>
                <p>testing</p>
            </details>

            <button onClick={() => setIsOpen(false)}>Open All Details.</button>
            <button onClick={() => setIsOpen(true)}>Close All Details.</button>
        </div>
    );
  }

ReactDOM.render(<SamplePage/>, document.getElementById("root"));

For the code snippet:

<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>

My question is how to combine these code segments. I've tried to construct this component in many different ways, but I can't get the button(s) to fire the onClick() effect. For example, I tried:

const React = require("react");

const SamplePage, {useState} = () => {
  const [isOpen, setIsOpen] = React.useState(false); 
  const siteConfig = this.props.config;

  return (
      <div>
          <details open={isOpen}>
              <summary>
                  First text detail.
              </summary>
              <p>testing</p>
          </details>
          <details open={isOpen}>
              <summary>
                  Second text detail.
              </summary>
              <p>testing</p>
          </details>
          <details open={isOpen}>
              <summary>
                  Third text detail.
              </summary>
              <p>testing</p>
          </details>

          <button onClick={() => setIsOpen(false)}>Open All Details.</button>
          <button onClick={() => setIsOpen(true)}>Close All Details.</button>
      </div>
  );
}

module.exports = SamplePage;

This throws an "invalid hook call", of course, since I can't actually use the useState hook in my current set-up. I get unexpected tokens and reference errors in all my other constructions.

Lichtung
  • 133
  • 2
  • 12

2 Answers2

1

You need to flip you're true/false bool in your onClicks (open should be true)

Keep in mind your 'open' onClick opens the drop-downs just fine but the 'close' onClick will only close the drop-downs if the 'open' onClick sets state to true first

If you need to export this instead of rendering it to the DOM (and can't/don't want to change to ES6 import statements elsewhere) then change ReactDom.render() to:

module.exports = SamplePage;

Full example:

const React = require('react')
const {useState} = React;

const SamplePage = (props) => {
    const [isOpen, setIsOpen] = useState(false); 
    const siteConfig = props.config

    return (
        <div>
            <details open={isOpen}>
                <summary>
                    First text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Second text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Third text detail.
                </summary>
                <p>testing</p>
            </details>

            <button onClick={() => setIsOpen(true)}>Open All Details.</button>
            <button onClick={() => setIsOpen(false)}>Close All Details.</button>
        </div>
    );
  }

module.exports = SamplePage;

Runnable snippet:

// const React = require('react')
const {useState} = React; //refer to above note

const SamplePage = (props) => {
    const [isOpen, setIsOpen] = useState(false);
    const siteConfig = props.config

    return (
        <div>
            <details open={isOpen}>
                <summary>
                    First text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Second text detail.
                </summary>
                <p>testing</p>
            </details>
            <details open={isOpen}>
                <summary>
                    Third text detail.
                </summary>
                <p>testing</p>
            </details>

            <button onClick={() => setIsOpen(true)}>Open All Details.</button>
            <button onClick={() => setIsOpen(false)}>Close All Details.</button>
        </div>
    );
  }

ReactDOM.render(<SamplePage/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Willman.Codes
  • 1,352
  • 1
  • 5
  • 13
  • This looks fine, but I still have to use `module.exports`. Otherwise, I get this error from the Docusaurus server: "Failed to start [...]: SyntaxError: 'import' and 'export' may appear only with 'sourceType: "module"'`. Can this error be avoided? – Lichtung Oct 28 '19 at 20:49
  • Where are you importing this component into? can you show that code? – Willman.Codes Oct 28 '19 at 20:54
  • It's all a bit over my head to be honest. The repository is [here](https://github.com/facebook/docusaurus). – Lichtung Oct 28 '19 at 20:57
  • Check my answer I updated to be more clear and added a clear example in addition to the runnable snippet – Willman.Codes Oct 28 '19 at 21:01
  • I tried the updated code. It looks right to me, but what do I know. This still throws the same error, unfortunately, with the 'sourceType: "module" restriction. – Lichtung Oct 28 '19 at 21:03
  • sorry try that now, you cant use import and module.exports in the same file. – Willman.Codes Oct 28 '19 at 21:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201515/discussion-between-lichtung-and-willman-codes). – Lichtung Oct 28 '19 at 21:11
1

I think you're getting object destructuring mixed up with imports. Here's a breakdown of what you should be doing:

// this line imports the react library, which we need in order to
// export a JSX component
const React = require("react");

// this line pulls the useState function out of the React library
// using object destructuring
const { useState } = React;
// it is the same as const useState = React.useState

// we dont need to pass useState in as a prop because its already
// imported in the same file
const SamplePage = props => {
  // and here we don't need to call React.useState because it has been
  // separated into its own variable
  const [isOpen, setIsOpen] = useState(false); 
  const siteConfig = props.config; // functional components don't use this

  return (
      <div>
          <details open={isOpen}>
              <summary>
                  First text detail.
              </summary>
              <p>testing</p>
          </details>
          <details open={isOpen}>
              <summary>
                  Second text detail.
              </summary>
              <p>testing</p>
          </details>
          <details open={isOpen}>
              <summary>
                  Third text detail.
              </summary>
              <p>testing</p>
          </details>

          <button onClick={() => setIsOpen(false)}>Open All Details.</button>
          <button onClick={() => setIsOpen(true)}>Close All Details.</button>
      </div>
  );
}

module.exports = SamplePage;

let me know if you have any more questions.

EDIT

I added the props parameter to the function, I accidentally left that out. Also, when using functional components you don't use the this keyword when accessing props, just call it on it's own.

Chris Sandvik
  • 1,787
  • 9
  • 19
  • This looks right, but I get this error: "TypeError: Cannot read property 'props' of undefined". – Lichtung Oct 28 '19 at 20:52
  • Just a general note, when you get the error "TypeError: Cannot read property 'ANYTHING' of undefined" that always means that the object the variable is a child of is undefined, not the variable itself. so in this case, `this` is undefined not `props` – Chris Sandvik Oct 28 '19 at 20:58
  • Your code loads just fine, but the buttons still don't have any effect. It's very strange. I'll need to do some more reading and testing, I suppose. – Lichtung Oct 28 '19 at 20:59
  • Where is the details element coming from? – Chris Sandvik Oct 28 '19 at 21:00
  • I'm not sure what you mean. It's a basic html tag. – Lichtung Oct 28 '19 at 21:04
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201516/discussion-between-lichtung-and-chris-sandvik). – Lichtung Oct 28 '19 at 21:20