ToggleButtons in react bootstrap won't reset - reactjs

Hello I am trying to make a component out of react bootstrap toggle group buttons using formik, the component works and pass the data correctly, but it just won't reset the buttons to "no button pressed at all" when I reset the form (the last pressed button is still checked,although the value of the togglebuttons being null(as intended)).
import React, { useState, useEffect } from "react";
import "./style.scss";
import { ToggleButtonGroup, ToggleButton } from "react-bootstrap";
const ToggleButtonsGrp = (props) => {
const [toggleValue, setToggleValue] = useState(props.state);
useEffect(() => {
props.formik.setFieldValue(props.formName, JSON.parse(toggleValue));
props.formik.setFieldTouched(props.formName);
}, [toggleValue]);
return (
<ToggleButtonGroup
id="toggleButtonGroup"
name="toggleButtonGroup"
className="toggleButtonGroup"
onChange={(value) => setToggleValue(value)}
>
{props.toggleButtons.map((opt) => (
<ToggleButton
key={opt.name}
id={`toggle-${opt.name}`}
type="radio"
name={props.formName}
className={`toggleBtn ${
opt.value === toggleValue ? "toggleBtn-Off" : "toggleBtn-active"
}`}
checked={opt.value === toggleValue}
value={opt.value}
>
{opt.name}
</ToggleButton>
))}
</ToggleButtonGroup>
);
};
tried to add a useEffect like this:
const [update,SetUpdate] = useState(0);
useEffect(() => {
if(!props.state) //when it resets or first time
setUpdate(update+1) //this would force a rerender
}, [props.state]);
It didn't solve the problem so I removed this.
The external form looks like this:
<Formik
initialValues={someFieldName:null}
onSubmit={(values, { resetForm }) => {
...//some logic
resetForm()
...
}}
>
{(formik)=>(
...
<ToggleButtonsGrp
toggleButtons={SomeButtons}
formName="someFieldName"
state={formik.values.someFieldName}
formik={formik}
/>
..
)}
</Formik>
while SomeButtons built like:
[{
name:"someName",
value:"someValue"
},
{
name:"someName2",
value:"someValue2"
}]

In the end I don't need to reset the form, leaving it if someone wants a challenge.
Sadly can't close the question myself.

Related

Adding updated state to code editor only works once

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>
);
}

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

React useEffect only works if I make a change to the code once the page is open

I'm having a problem in React where the code I have for my useEffect in a component works, but only if I manually make a change to the code (not even a substantial one, it can be as small as adding or removing a console.log) after loading the component. Here's a link to a screen recording of what happens.
I am using the Material-UI Autocomplete component to create a list, but it's like the useEffect won't actually kick in when I load the page with the component until I make some sort of change to the code after the component loads (again: even something as small as commenting out or adding a console.log works). Once I make that change, the list will appear. But if I navigate away from the page or reload, I'm back to square 1 again.
Similarly, when I try to select an option in the list, it looks as if it didn't work until I make a change to the code. Only then will the selection change I made to the list appear.
Here's the code I have for that component:
import React, { useState, useEffect } from 'react'
import { makeStyles } from '#material-ui/core/styles'
import Checkbox from '#material-ui/core/Checkbox'
import TextField from '#material-ui/core/TextField'
import Autocomplete from '#material-ui/lab/Autocomplete'
import Typography from '#material-ui/core/Typography'
import CheckBoxOutlineBlankIcon from '#material-ui/icons/CheckBoxOutlineBlank'
import CheckBoxIcon from '#material-ui/icons/CheckBox'
const icon = <CheckBoxOutlineBlankIcon fontSize='small' />
const checkedIcon = <CheckBoxIcon fontSize='small' />
const useStyles = makeStyles((theme) => ({
root: {
margin: 'auto'
},
paper: {
width: 250,
height: 230,
overflow: 'auto',
backgroundColor: '#bdbdbd'
},
button: {
margin: theme.spacing(0.5, 0)
},
checkbox: {
color: '#FFF342'
},
textfield: {
backgroundColor: '#bdbdbd'
}
}))
const WordSelect = ({ newListState, setNewListState }) => {
// const WordSelect = ({ newListState, setNewListState }) => {
const classes = useStyles()
const [wordsText, setWordsText] = useState({
wordOptions: []
})
useEffect(() => {
const wordsText = []
newListState.words.map(x => {
wordsText.push(x.text)
})
// console.log(wordsText)
setWordsText({ ...wordsText, wordOptions: wordsText })
}, []) // eslint-disable-line react-hooks/exhaustive-deps
return (
<>
<Autocomplete
multiple
id='checkboxes-tags-demo'
disableCloseOnSelect
value={newListState.selected}
options={wordsText.wordOptions}
getOptionLabel={(option) => option}
getOptionSelected={(option, value) => option === value}
onChange={(event, newValue) => {
newListState.selected = newValue
}}
renderOption={(option, { selected }) => (
<>
<Checkbox
className={classes.checkbox}
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
<Typography className={classes.checkbox}>
{option}
</Typography>
</>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField {...params} className={classes.textfield} variant='outlined' placeholder='Select Words' />
)}
/>
</>
)
}
export default WordSelect
I'm really not sure what's going on. It seems like the code must be right since the types of changes I make to get it to show up should have no effect on what renders on the page, but then why won't it render from the start? Any tips appreciated.
You have not added newListState to your useEffect dependency array. Therefore, useEffect runs only on the first render of the component. When you do a change in code, live reload reloads the component and the useEffect hook runs.
Try this:
useEffect(() => {
const wordsText = []
newListState.words.map(x => {
wordsText.push(x.text)
})
// console.log(wordsText)
setWordsText({ ...wordsText, wordOptions: wordsText })
}, [setWordsText, newListState])
You really shouldn’t be using ‘ // eslint-disable-line react-hooks/exhaustive-deps’ as it helps catch problems like these. It also might help you catch some nasty bugs due to stale data or functions.

How to disable the Text field name is disappearing when we moved out the input filed box in react js

I have made autocomplete features using Downshift using react js. But the problem is when I am searching for something its input field value is disappearing when I click on the outside. Here is the sample code.
import logo from './logo.svg';
import './App.css';
import React, { useState } from "react";
import Highlighter from "react-highlight-words";
import Downshift from "downshift";
import axios from 'axios';
function App() {
const [names, setnames] = useState([{
const [searchTerm, setSearchTerm] = useState('')
const [movie, setmovie] = useState([])
fetchMovies = fetchMovies.bind(this);
inputOnChange = inputOnChange.bind(this);
function inputOnChange(event) {
if (!event.target.value) {
return;
}
fetchMovies(event.target.value);
}
function downshiftOnChange(selectedMovie) {
alert(`your favourite movie is ${selectedMovie.title}`);
}
function fetchMovies(movie) {
const moviesURL = `https://api.themoviedb.org/3/search/movie?api_key=1b5adf76a72a13bad99b8fc0c68cb085&query=${movie}`;
axios.get(moviesURL).then(response => {
setmovie(response.data.results);
// this.setState({ movies: response.data.results });
});
}
return (
<Downshift
onChange={downshiftOnChange}
itemToString={item => (item ? item.title : "")}
>
{({
selectedItem,
getInputProps,
getItemProps,
highlightedIndex,
isOpen,
inputValue,
getLabelProps
}) => (
<div>
<label
style={{ marginTop: "1rem", display: "block" }}
{...getLabelProps()}
>
Choose your favourite movie
</label>{" "}
<br />
<input
{...getInputProps({
placeholder: "Search movies",
onChange: inputOnChange
})}
/>
{isOpen ? (
<div className="downshift-dropdown">
{movie
.filter(
item =>
!inputValue ||
item.title
.toLowerCase()
.includes(inputValue.toLowerCase())
)
.slice(0, 10)
.map((item, index) => (
<div
className="dropdown-item"
{...getItemProps({ key: index, index, item })}
style={{
backgroundColor:
highlightedIndex === index ? "lightgray" : "white",
fontWeight: selectedItem === item ? "bold" : "normal"
}}
>
{item.title}
</div>
))}
</div>
) : null}
</div>
)}
</Downshift>
);
}
export default App;
This is the sample code I have written. Also, when I click shift+home, it is also not working.
Problem 1: when the user clicked the outside text field value whatever I searched this is disappearing.
Problem 2: shift + home is not working also.
Anyone has any idea how to solve this problem?
when the user clicked the outside text field value whatever I searched this is disappearing.
One way you could do it is to set the stateReducer on the Downshift component:
This function will be called each time downshift sets its internal state (or calls your onStateChange handler for control props). It allows you to modify the state change that will take place which can give you fine grain control over how the component interacts with user updates without having to use Control Props. It gives you the current state and the state that will be set, and you return the state that you want to set.
state: The full current state of downshift.
changes: These are the properties that are about to change. This also has a type property which you can learn more about in the stateChangeTypes section.
function stateReducer(state, changes) {
switch (changes.type) {
case Downshift.stateChangeTypes.mouseUp:
return {
...changes,
isOpen: true,
inputValue: state.inputValue,
};
default:
return changes;
}
}
This way if you click outside the text field the dropdown will stay open and the input value won't be reset.
For a list of all state change types see the documentation here
You might also be able to get something working using the onBlur prop on the input, but I didn't get that working.

Resources