Adding updated state to code editor only works once - reactjs

I have an issue with my code below. When you click the add code button, it adds the code to the monaco code editor which is great. However, if you type some more code in the editor or erase whats currently there and then press the 'Add code' button, nothing is added. It's just blank.
Is there a way to whenever that 'Add code' button is clicked it clears everything in the editor and just adds the setAddCode state when the button is clicked?
And here is the code:
import { useState, useRef, useEffect } from "react";
import Editor from "#monaco-editor/react";
export default function IndexPage() {
const [input, setInput] = useState("");
const [addCode, setAddCode] = useState("# code goes here");
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
setInput((editorRef.current = editor));
editorRef.current = editor;
}
return (
<div>
<div className="code-editor">
<Editor
width="100vh"
height="40vh"
theme="vs-dark"
fontSize="14"
defaultLanguage="python"
defaultValue=""
value={addCode}
onMount={handleEditorDidMount}
/>
</div>
<br />
<button onClick={() => setAddCode("print('Hello World!')")}>
Add code
</button>
</div>
);
}

The way the Editor component is set up, it will only change the value in the editor if you pass a different value prop. It's probably doing something similar to the following:
const Editor = ({ value }) => {
const [codeToDisplay, setCodeToDisplay] = useState(value);
useEffect(() => {
setCodeToDisplay(value);
}, [value]);
// etc
In your parent component, when you call setAddCode("print('Hello World!')") the first time, that'll result in the child component seeing a difference in how it was called - the value prop changed - so it'll know that there's something different to display, and update its own internal state appropriately. When you press the button again, the addCode value will stay the same - the Editor component doesn't see any difference, so it won't update.
To fix it, you can listen for changes from inside Editor by using its onchange prop to update the state in the parent component when the code inside the editor changes - that way, when you click the button later, the prop will be different, and the editor will know to update its internal state.
export default function IndexPage() {
const [input, setInput] = useState("");
const [codeValue, setCodeValue] = useState("# code goes here");
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
setInput((editorRef.current = editor));
editorRef.current = editor;
}
return (
<div>
<div className="code-editor">
<Editor
width="100vh"
height="40vh"
theme="vs-dark"
fontSize="14"
defaultLanguage="python"
defaultValue=""
value={codeValue}
onChange={(newValue) => { setCodeValue(newValue); }}
onMount={handleEditorDidMount}
/>
</div>
<br />
<button onClick={() => setCodeValue("print('Hello World!')")}>
Add code
</button>
</div>
);
}

Related

React- how to enable a button when TextField has value

So I'm trying to enable a button as soon as I enter a value in the TextField. The only way it is enabled is if i click outside the TextField after I put a value inside the Textfield. I know i'm missing something small but I still haven't found the correct way. I would appreciate your advice .
The code for the TextField and LoadingButton
the Window
I have included only the relevant part.
import { useState } from "react";
export default function Home() {
const [name, setName] = useState("");
const hanldeUserInput = (e) => {
setName(e.target.value);
};
return (
<Dialog>
<TextField onChange={hanldeUserInput} value={name} />
<LoadingButton disabled={name === ""}>Save</LoadingButton>
</Dialog>
);
}
You could keep track of the current value inside your textfield and store it inside the state.
const [txtFieldValue, setTxtFieldValue] = useState<string>('')
and write a function which is triggered on the change event in your textfield:
function handleTxtFieldChange(event) {
if (event.target.id === 'myTextFieldId') {
setTxtFieldValue(event.target.value)
}
}
And then you can adjust your textfield:
<TextField
id={'myTextFieldId'}
// ... all your other stuff
onChange={(event) => {
handleTxtFieldChange(event)
}}
/>
and you can then use the set txtFieldValue to render the button like:
{txtFieldValue != '' ? <Button /> : <></>}
or if you just want to disable it you can just use the
txtFieldValue != ''
as a boolean.

How to turn off toggle button by clicking other button in React JS?

Basically, we can turn off/on toggle button by clicking the toggle button. How can I turn off toggle by clicking other button (what is generated after turning on toggle) like this:
Sadly, I can only hidden the button by clicking it but not the toggle by using my current code...
You need to manage a state for the toggle switch through the external button click.
This is a reference code that should get you started.
import React from "react";
export default function App() {
const [isOn, setIsOn] = React.useState(false);
return (
<>
<input
type="checkbox"
checked={isOn}
onClick={(e) => setIsOn(e.target.val)}
/>
<br />
<button onClick={() => setIsOn((prevState) =>
!prevState)}>Toggle</button>
</>
);
}
This code is available here:
https://codesandbox.io/s/hungry-knuth-55eh0?file=/src/App.js
As the toggle switch is a component of my employer, I just use checkbox to replace in this example.
I think I can code for my question (as you can see my code shown as below) and I found why the toggle switch cannot be turned off by a button... It is because there is a bug in the toggle switch component of my employer and then I have eventually fixed the bug.
Anyway, let me show the code for this question (even it is not the answer for the fixing the bug that I really need):
import React from "react";
import "./styles.css";
export default function App() {
const [isOn, setIsOn] = React.useState(
{ a: false , b: false, c: false }
);
const handleInputA = () => {
setIsOn({ ...isOn, a: !isOn.a });
}
const handleInputB = (inputLabel) => {
setIsOn({ ...isOn, b: !isOn.b });
}
const handleInputC = (inputLabel) => {
setIsOn({ ...isOn, c: !isOn.c });
}
return (
<>
<input
type="checkbox"
checked={isOn.a}
onClick={handleInputA}
/>a
<br />
<input
type="checkbox"
checked={isOn.b}
onClick={handleInputB}
/>b
<br />
<input
type="checkbox"
checked={isOn.c}
onClick={handleInputC}
/>c (The one that I want to do for this question.)
<br />
{ isOn.c &&
<button onClick={handleInputC}>Unselect C</button>
}
</>
);
}
You may check to see the effect if you are interested: https://codesandbox.io/s/toggleswitch-tpkti

Function call and pass value in the same OnClick - React

I got a OnClick which actually receives an id:
<Button onClick={() => addToCart(id)} >Buy</Button>
On the other hand, in a different JS file,I got a modal which appears with a click via useState:
const [stateModal1, changeModalState1] = useState(false);
Now, in the same component I work with this modal, I map an array which returns a Button, which now is working with the "addToCart(id)" value mentioned before, like this:
{products.map((product) => {
return <Product image={product.image}
key={product.id}
data={product}
addToCart={() =>addToCart(product.id)} />})}
The question that is driving me crazy is: how can I use the button in the mapped array to trigger that modal, and at the same time, to pass values to that modal in order to show the mapped item IN that modal?
Thanks in advance.
EDIT: this is the modal, which is another component:
const Modal = ({
children,
state,
stateModal1,
})
return (
<>
{state &&
<Overlay>
<Container>
<CloseButton onClick={() => changeState(false)}>{FaWindowClose}</CloseButton >
{children}
<Header>
<h3>Confirm buy</h3>
<h4>{name}</h4>
<h4>$ {price}</h4>
</Header>
<Button onClick={() => changeState(false)}>Confirm</Button>
</Container>
</Overlay>
}
</>)
PS: the "confirm" button which triggers the "changeState()", should also trigger the addToCart().
As mentioned by other comments above, you can pass a prop to the modal component from the parent component to achieve your demand normally.
The only thing that needs to be done is set the open/close modal state and the passing data state at the same time, or, probably use one state directly
sample of the code:
import "./styles.css";
import "antd/dist/antd.css";
import { useState } from "react";
import { Modal } from "antd";
export default function App() {
// init with undefined, if not undefined, open the modal
const [modal, setModal] = useState(undefined);
const list = [...Array(20).keys()];
// set the state to open the modal, as well as pass it to the modal itself as a prop if necessary
const handleClick = (idx) => () => {
setModal(idx);
};
return (
<div className="App">
{list.map((x, idx) => (
<div style={{ border: "1px solid black" }} onClick={handleClick(idx)}>
{x}
</div>
))}
<Modal visible={modal !== undefined}>The value you passed: {modal}</Modal>
</div>
);
}
the online demo could be found here: https://codesandbox.io/s/hardcore-shape-89y78?file=/src/App.js

Persistent way for getting an Input Value using Hooks

I'm a beginner at React. I'm trying to build a component that recovers the text of an input and later on inserts it on the HTML.
import React, { useState } from 'react';
function InputGetter(){
const [text, setText] = useState("")
let typed = ""
return(
<div>
<input type='text' onChange = {(e)=> typed = e.target.value}></input>
<button onClick={() => setText(typed)}>Set Text</button>
Text typed was "{text}"
</div>
)
}
export default InputGetter
The code above works for clicks when there's a change triggered. However, when I try to double click it, even when there's content on the input, text somehow is set to "". I'm not sure why it happens. How can I make the textvariable content persistent?
You have closure on text value within the onClick callback, to persist value between renders, you can use useRef hook, see Is there something like instance variables?.
function InputGetter() {
const [text, setText] = useState('');
const inputRef = useRef('');
return (
<div>
<input type="text" ref={inputRef}></input>
<button onClick={() => setText(inputRef.current.value)}>Set Text</button>
Text typed was "{text}"
</div>
);
}

Custom react hook to set input form not working

I've tried creating a custom hook, following the examples an article about handling forms in react using hooks. I should also add I'm very new to react.
This is the content of hooks/useInput.js:
import { useState } from "react";
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(event) {
console.log(event.target.name);
console.log(event.target.value);
setValue(event.target.value);
}
return [value, handleChange];
}
export default useInput;
In a component I have the following:
import useInput from "hooks/useInput";
export default function Address(props) {
const [fullName, setFullName] = useInput("");
return (
<FormControl fullWidth>
<CustomInput
required
labelText="Full name"
id="fullName"
formControlProps={{
fullWidth: true
}}
value={fullName}
onChange={setFullName}
/>
</FormControl>
);
}
When I try to input some text (or even if I try to change the default state), nothing happens.
Any breakpoint that I set in useInput.js are not hit and no logging appears in the console.
Where am I going wrong?
If you want to see your current input value with a button click you can see like this. I didn't even change your userInput.js file. I can see the updated value by doing this and console as well.
export default function Address(props) {
const [fullName, setFullName] = useInput("");
return (
<>
<input
placeholder="Name"
value={fullName}
onChange={setFullName}
/>
<button onClick={() => {
console.log(fullName);
}}>Submit</button>
</>
);
}
Since I don't know about your CustomInput, I have written this with default input and button. Please check your CustomInput correctly. Because default input is working.

Resources