update the defaultValue on re - reactjs

Here in the input box, I am passing an initial value by useState hook. Now suppose I type in the input field and re-render the component by clicking the 'change' button, it still shows the typed input value.
But I want to have the initial value when the component re-renders. How to do that?
import React , { useState, useEffect } from "react";
import "./styles.css";
export default function App({val}) {
const [value, setValue] = useState(val);
const [x, setX] = useState(100);
const handleChange = (e) => {
console.log(e.target.value)
setValue(e.target.value)
}
const handleClick = () => {
console.log('l')
setX(10)
}
useEffect(() => {
console.log('ef')
}, [x])
return (
<div className="App">
<input
name="box"
value={value}
onChange={handleChange}
/>
{x}
<button onClick={() => handleClick()}>Change</button>
</div>
);
}

You can just reset your value state on that button click i.e.
const handleClick = () => {
setValue(val);
setX(10)
}

Related

Reactjs Debounce search field re-renders component if the field is not empty

I am trying to create a debounce search and initially when the field is empty the component renders after the provided setTimeout delay. But if I continue to search with the existing keyword it re-renders the List component on each key stroke. How to avoid that?
import { useEffect, useState } from 'react';
import useDebounce from './hooks/useDebounce';
import List from './components/List';
const App: React.FC = () => {
const [todo, setTodo] = useState<string>("");
const [query, setQuery] = useState<string | null>("");
let deBounceSearch = useDebounce(query, 2000);
useEffect(() => {
if (deBounceSearch) {
console.log('Searching...');
} else {
console.log('...');
}
}, [deBounceSearch]);
return (
<div className="App">
<input type="text" placeholder='Search anything' onChange={(e) => setQuery(e.target.value)} />
{deBounceSearch !== '' && (
<List />
)}
</div>
);
}
useDebounce.tsx
const useDebounce = (value: any, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => { setDebouncedValue(value) }, delay);
return () => {
clearTimeout(handler);
}
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;
You can use useMemo to avoid re-render the List component every time query value changes:
const App: React.FC = () => {
const [todo, setTodo] = useState<string>("");
const [query, setQuery] = useState<string | null>("");
const deBounceSearch = useDebounce(query, 2000);
// ->
const cachedList = React.useMemo(() => <List />, [debouncedValue]);
...
return (
<div className="App">
<input type="text" placeholder='Search anything' onChange={(e) => setQuery(e.target.value)} />
{deBounceSearch !== '' && cachedList}
</div>
);
}
You also can take a look at React.memo
hello man this is not the best to use debounce i suggest u try lodash debounce with useMemo.
but for now the solution for your code is that you forgot to clear the timeout on every time the value change.
here the solution:
import { useEffect, useState, useRef } from "react";
import "./styles.css";
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
const handler = useRef();
useEffect(() => {
if (handler.current) {
clearTimeout(handler.current);
}
handler.current = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler.current);
};
}, [value, delay]);
return debouncedValue;
};
export default function App() {
const [value, setValue] = useState("");
const debounceSearch = useDebounce(value, 2000);
console.log(debounceSearch);
return (
<div className="App">
<input value={value} onChange={(e) => setValue(e.target.value)} />
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
hope this help .

React, why state doesn't change?

It's a simple example about derived state.
Here is the sandbox url: https://codesandbox.io/s/review-react-derived-state-2-forked-v9ucpr?file=/src/App.js
I expected value change 0 to 10, when I click the button. But, it doesn't rendering also, its flow is weired.
I click button several times, it doesn't re-render, even though changing the value.
Here is the code:
import { useState, useEffect } from "react";
export default function App() {
console.log("App is called!");
const [value, setValue] = useState(() => {
console.log("App useState is alloc");
return 0;
});
console.log("App is END");
return (
<div>
<NumberInput value={value} onChange={setValue} />
<button onClick={() => setValue(10)}>change to ten</button>
</div>
);
}
function NumberInput({ value, onChange }) {
console.log(" NumberInput is called!");
const [inputValue, setInputValue] = useState(value);
useEffect(() => {
const numberValue = Number(inputValue);
onChange(numberValue);
}, [inputValue, onChange]);
console.log(" NumberInput is END");
return (
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
);
}
Your
const [inputValue, setInputValue] = useState(value);
"forks" the prop value to local state, so changes to value won't be reflected in inputValue after initial mount.
You'd need
useEffect(() => setInputValue(value), [value]);
in the child component to mirror any changes to the value prop to inputValue too.
You are not updating the internal state of the NumberInput when the value changes.
This would be the code that solves the issue:
import { useState, useEffect } from "react";
export default function App() {
const [value, setValue] = useState(0);
return (
<div>
<NumberInput value={value} onChange={setValue} />
<button onClick={() => setValue(10)}>change to ten</button>
</div>
);
}
function NumberInput({ value, onChange }) {
const [inputValue, setInputValue] = useState(value);
useEffect(() => {
onChange(+inputValue);
}, [inputValue, onChange]);
// We add a use effect that will get trigger when the parent
// value changes
// However, this implies that the NumberInput will always render
// because of the previous useEffect, which also updates the
// value's value
useEffect(() => {
setInputValue(`${value}`);
}, [value]);
return (
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
);
}
useState will catch your value only on initialising the child component.
Try:
<input value={value}
// instead of
<input value={inputValue}
I hope that is what you wanted!

React state array (first input not working)

why I can't set the Data in the first Click I Have to input twice to set the data.
Thanks for your help...
export default function App() {
const [title, setTitle] = useState();
const [projectData, setProjectData] = useState([]);
const handleSubmit = (e) => {
e.preventDefault();
setProjectData([...projectData, { projectTitle: title }]);
console.log(projectData);
};
return (
<div className="App">
<input
type="text"
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<button onClick={handleSubmit}>insert</button>
</div>
);
}
Actually it did, but the setState hook runs asynchronously so the console.log after that won't reflect the change. You could use useEffect to watch for the change of projectData instead
import React, { useEffect, useState } from "react";
export default function App() {
const [title, setTitle] = useState();
const [projectData, setProjectData] = useState([]);
useEffect(() => {
console.log(projectData);
}, [projectData]);
const handleSubmit = (e) => {
e.preventDefault();
setProjectData([...projectData, { projectTitle: title }]);
};
return (
<div className="App">
<input
type="text"
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<button onClick={handleSubmit}>insert</button>
</div>
);
}
In React setState actions are asynchronous and are batched for performance gains. This is explained in the documentation of setState.
If you want to log projectData you can use useEffect hook.
const handleSubmit = (e) => {
e.preventDefault();
setProjectData([...projectData, { projectTitle: title }]);
};
// useEffect with ProjectData as dependency
useEffect(() => {
console.log(projectData);
}, [projectData]);

useEffect with local variable

I am trying to call useEffect funtion onchange of local variable, but its not working is only works if i use it with useState variable, I know there might be some basic thing here that I am not aware of.
sandbox link: https://codesandbox.io/s/affectionate-gareth-igyv7?file=/src/demo.js
import React, { useEffect, useState } from "react";
import "./styles.css";
export default function Demo() {
const [value, setValue] = useState("");
let valueOne, valueTwo;
const setValueOne = (value) => {
valueOne = value;
};
useEffect(() => {
console.log(value);
console.log(valueOne);
}, [value, valueOne]);
return (
<div>
<h1>Demo</h1>
<input
placeholder="useState"
onChange={(e) => setValue(e.target.value)}
/>
<input
placeholder="function"
onChange={(e) => setValueOne(e.target.value)}
/>
{/* {console.log(valueOne)} */}
</div>
);
}
setValueOne will not rerender your component, If you want to fire a re-render, useEffect function needs to have a useState which basically hold state between re-renders.
You can try managing your state like below, its more readable and it will work too.
import React, { useState } from "react";
import "./styles.css";
export default function Demo() {
const [valueOne, setValueOne] = useState("");
const [valueTwo, setValueTwo] = useState("");
const handleValueOne = (e) => {
setValueOne(e.target.value);
};
const handleValueTwo = (e) => {
setValueTwo(e.target.value);
};
return (
<div>
<h1>Demo</h1>
<input
value={valueOne}
placeholder="useState"
onChange={handleValueOne}
/>
<input
value={valueTwo}
placeholder="function"
onChange={handleValueTwo}
/>
{/* {console.log(valueOne)} */}
</div>
);
}

Problem setting disabled prop and focus from the same function

I'm trying to build edit form fields. Here, you have to press a button before you can edit the form field. However, I'm having problems toggling the disabled prop and setting the focus of the element. This is some sample code. The input will only focus after I've clicked the button twice.
export default function App() {
const [isDisabled, setIsDisabled] = useState(true);
const inputEl = useRef(null);
const onBlur = () => {
setIsDisabled(true);
};
const handleEditClick = () => {
setIsDisabled(false);
inputEl.current.focus();
};
return (
<div className="App">
<h1>Focus problem</h1>
<h2>Focus only happens on the scond click!</h2>
<input ref={inputEl} onBlur={onBlur} disabled={isDisabled} />
<button onClick={() => handleEditClick()}>Can edit</button>
</div>
);
}
Here is a code-sandbox
Setting focus on a DOM element is a side-effect, it should be done within useEffect:
import React, { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function App() {
const [isDisabled, setIsDisabled] = useState(true);
const inputEl = useRef(null);
useEffect(() => {
inputEl.current.focus();
}, [isDisabled]);
const onBlur = () => {
setIsDisabled(true);
};
const handleEditClick = () => {
setIsDisabled(false);
};
return (
<div className="App">
<h1>Focus problem</h1>
<h2>Focus only happens on the scond click!</h2>
<input ref={inputEl} onBlur={onBlur} disabled={isDisabled} />
<button onClick={() => handleEditClick()}>Can edit</button>
</div>
);
}

Resources