I have multiple rows, each row contains two text inputs and a button. When user focuses on one of the inputs, the button should be shown. When elements lose focus, the button should become invisible once again. My best attempt:
const Input = ({inputRef}) => {
return (
<>
<h1>Input</h1>
<input type="text" ref={inputRef}/>
</>
)
}
export default () => {
const firstRef = useRef(null);
const secondRef = useRef(null);
const it = useRef(null);
const [editing, setEditing] = useState(false);
function handleClick(e) {
firstRef.current.focus();
}
function handleSave() {
console.log("saving!");
}
function checkFocus(e) {
if (!it.current.contains(document.activeElement)) {
setEditing(false);
} else {
setEditing(true);
}
}
useEffect(() => {
document.body.addEventListener("focus", checkFocus, true);
return () => {
document.body.removeEventListener("focus", checkFocus, true);
}
}, []);
return (
<div ref={it}>
<Input inputRef={firstRef}/>
<Input inputRef={secondRef}/>
<button type="button" onClick={handleSave} style={{visibility: editing ? "visible" : "hidden"}}>Save</button>
<button type="button" onClick={handleClick}>Edit</button>
</div>
)
}
Is there any better/more elegant and efficient way of achieving this?
CodePudding user response:
Here's a solution to what you're attempting using only CSS, which in my opinion makes it more elegant (and ever so slightly more performant, but really this is negligible).
https://codepen.io/danny_does_stuff/pen/QWMprMJ
<div>
<input id="input1" />
<input id="input2" />
<button id="save-button">Save</button>
<button id="edit-button">Edit</button>
</div>
<style>
input#input2:focus button#save-button {
visibility: hidden;
}
</style>
If you wanted to do it in a more React way, you could do what Marco B suggested in his answer
CodePudding user response:
You can use onBlur
and onFocus
events.
This should work as expected, just adapt the logic on your component
EDIT
Edited the onBlur method.
const INITIAL_STATE = {
input: ''
}
export default function App() {
const [show, setShow] = useState(false);
const [value, setValue] = useState(INITIAL_STATE);
const handleChange = (e) => {
const { value, name } = e.target;
setValue(prevState => ({ ...prevState, [name]: value }))
}
const onBlur = () => {
if (!value.input) {
setShow(false)
}
}
return (
<>
<Input name="input" onChange={handleChange} value={value.input} onFocus={() => setShow(true)} onBlur={onBlur} />
{show && <button>TEST</button>}
</>
);
}
const Input = (props) => {
return (
<>
<h1>Input</h1>
<input {...props} type="text" />
</>
);
};