=> how about wrapping with an array? ([])
... it can trigger a "key" warning
... then... how about providing a unique key for each element?
... it might be cumbersom
=> we can solve this problem by wrapping with div element
... we can end-up with div soup (in a final HTML page)
... it results in unnecessary div elements(no semantic meaning or structure to the page)
const Wrapper = props => {
return props.children;
};
export default Wrapper;
// can use <Wrapper></Wrapper> instead of <div></div>
We use portals to get a cleaner DOM with Portals
Like by the name literally Portal,
it moves rendered HTML content to other place in the DOM structure
index.html
// add a code
// can also manage each components seperately
<div id="backdrop-root"></div> // all kids of backdrops
<div id="overlay-root"></div> // all kinds of overlays: modal, side-drawbars etc...
<div id="root"></div>
ErrorModal.js
// import ReactDOM
import ReactDOM from 'react-dom'
const Backdrop = props => {
return (
// Code related to backdrops
<div className = {classes.backdrop} onClick={props.onConfirm} />
)
}
const ModalOverlay = props => {
return (
// Code related to modal
<Card className={classes.modal}>
<header className={classes.header}>
<h2>{props.title}</h2>
</header>
<div className={classes.content}>
<p>{props.message}</p>
</div>
<footer className={classes.actions}>
<Button onClick={props.onConfirm}>Okay</Button>
</footer>
</Card>
)
}
const ErrorModal = (props) => {
return (
<React.Fragment>
⭐{ReactDOM.createPortal(<BackDrop onConfirm = {props.onConfirm})/>
, document.getElementById('backdrop-root')}
⭐{ReactDOM.createPortal(
<ModalOverlay
title={props.title}
message={props.message}
onConfirm={props.onConfirm}
/>,
document.getElementById('overlay-root')
)}
</React.Fragment>
);
ref(reference)
Thinking about input tags in form,
we used useState() to manage the input contents(two-way binding)
But since we actually neet the content only when we submit the form
, this way seems a bit unnecessary
In this situation, we can use useRef
We also use useRef in a situation where
we only want to read a value
controlled component
: when the internal state is managed by react
(useState)
un-controlled component
: when the internal state is not managed by react
(useRef)
// import useRef
import React, { useState, useRef } from 'react';
const AddUser = (props) => {
const nameInputRef = useRef();
const ageInputRef = useRef();
// if checking it with console.log(),
// it returns an object with 'current' property
// in the 'current' property,
// it containts the actual DOM node.
const addUserHandler = (event) => {
event.preventDefault();
// can read the input value by .current.value
const enteredName = nameInputRef.current.value;
const enteredUserAge = ageInputRef.current.value;
props.onAddUser(enteredName, enteredUserAge);
// resetting an input value
nameInputRef.current.value = '';
ageInputRef.current.value = '';
};
return (
<Wrapper>
<Card className={classes.input}>
<form onSubmit={addUserHandler}>
<label htmlFor="username">Username</label>
<input id="username" type="text" ref={nameInputRef} />
<label htmlFor="age">Age (Years)</label>
<input id="age" type="number" ref={ageInputRef} />
<Button type="submit">Add User</Button>
</form>
</Card>
</Wrapper>
);
};
export default AddUser;
hook that interact with the input components imperatively
(not by parsing some state to it that then changes something in the component but by calling a function inside of a component)
(shouldn't do often because it is not a typical pattern)
can expose functionalities from a React component to its parent component
to then use your component in the parent component through refs and trigger certain functionalities
can be used on particular behavior such as focusing or scrolling (a situation where we need to approach a child component's DOM event)
Ref 전달하기는 일부 컴포넌트가 수신한 ref를 받아 조금 더 아래로 전달
(즉, “전송”)할 수 있는 옵트인 기능입니다
=> want to focus the first invalid input found
Input.js
import React, {useRef, useImperativeHandle} from 'react'
const Input = ✨React.forwardRef((props, ✨ref) => {
// 2️⃣ ref를 전달받음
⭐const inputRef = useRef();
// a rare case to use
✨const activate = () => {
inputRef.current.focus();
}
✨useImperativeHandle(ref, () => {
// 3️⃣ can use focus(activate) function in the parent component
return {
focus : activate
}
});
return (
<input
⭐ref={inputRef}
/>
)
});
Login.js
const Login = () => {
const submitHandler = (event) => {
event.preventDefault();
if (formIsValid) {
authCtx.onLogin(emailState,value, passwordState.value);
} else if (!emailIsValid) {
✨3️⃣ emailInputRef.current.focus();
} else {
✨3️⃣ passwordInputRef.current.focus();
}
}
⭐const emailInputRef = useRef();
⭐const passwordInputRef = useRef();
return (
// 1️⃣ Input component에 ref를 전달함
<Input
⭐ref = {emailInputRef}
/>
<Input
⭐ref = {passwordInputRef}
/>
)
}