2

I have a large project with multiple files. I want a button to render the content of some other components upon clicking. I am trying to understand why the following does not work, and what could I do to make it work instead?

Index.js

import React from "react";
import ReactDOM from "react-dom";

import { unitState, setUnitState } from './changeUnit.js'


function App() {
  return (
    <div>
      <h1>{unitState}</h1>

      <button onClick={setUnitState("°C")}>°C</button>
      <button onClick={setUnitState("°F")}>°F</button>
    </div>
  );
}

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

changeUnit.js

export let unitState = "°C";
export function setUnitState(unit) {
    (unit==="°C") ? unitState="°C" : unitState="°F";
}

with codesandbox link here


Currently, upon clicking any of the buttons the text does not change. But the code does reach inside the setUnitState method. I suspect that is because the main component is not rerendering. I tried to change my changeUnit.js code to

import App from './index.js';

export let unitState = "°C";
export function setUnitState(unit) {
    (unit==="°C") ? unitState="°C" : unitState="°F";
    App.forceUpdate();
}

but I get the error _index.default.update is not a method.

I have tried to use the useState hook from React but I just can't make it work for the life of me. I have tried many combinations but it seems that I can't return the setState function as a return from the custom hook.

Does anyone know how I can solve this problem?

1
  • 3
    What's the problem with useState? Commented Jul 30, 2021 at 21:30

3 Answers 3

2

I'm not sure why you're not using the useState hook, or what went wrong with your custom hook.

With useState():

function App() {
  let [unitState, setUnitState] = React.useState('°C')
  
  return (
    <div>
      <h1>{unitState}</h1>
      <button onClick={() => setUnitState('°C')}>°C</button>
      <button onClick={() => setUnitState('°F')}>°F</button>
    </div>
  );
}

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

With custom hook:

function App() {
  let { unitState, setCelsius, setFahrenheit } = useSwitch()
  
  return (
    <div>
      <h1>{unitState}</h1>
      <button onClick={setCelsius}>°C</button>
      <button onClick={setFahrenheit}>°F</button>
    </div>
  );
}

function useSwitch() {
  let [unitState, setUnitState] = React.useState('°C')
  let setCelsius = () => setUnitState('°C')
  let setFahrenheit = () => setUnitState('°F')
  return { unitState, setCelsius, setFahrenheit }
}

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. But say I have another file component.js where the <h1>{unitState}</h1> is present. How to I pass it the unitState value ? Do I have to call again let { unitState, setCelsius, setFahrenheit } = useSwitch() because that doesn't work in my case.
You're welcome. In that case, you'll either need to lift the state or use context. This might help: stackoverflow.com/questions/53451584/…
1

I'm guessing you probaly weren't using useState right. this is fairly simple with use state.

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

// import { unitState, setUnitState } from "./changeUnit.js";

function App() {
  const [unitState, setUnitState] = useState("°C");
  return (
    <div>
      <h1>{unitState}</h1>

      <button onClick={() => setUnitState("°C")}>°C</button>
      <button onClick={() => setUnitState("°F")}>°F</button>
    </div>
  );
}

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

Comments

1

I think you should just use setState, it might be the case that you were trying to call the setState without the lambda?

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

function App() {
  const [unitState, setUnitState] = useState("C");

  return (
    <div>
      <h1>{unitState}</h1>

      <button onClick={() => setUnitState("C")}>C</button>
      <button onClick={() => setUnitState("F")}>F</button>
    </div>
  );
}

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

https://codesandbox.io/s/changeunitstate-forked-zbrym

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.