리액트 후크 방식으로 요청을 보내는 방법
리액트 훅을 사용하여 버튼 클릭 시 http 요청을 전송하려면 어떻게 해야 합니까?아니면 버튼 클릭에 대한 부작용은 어떻게 해야 할까요?
지금까지 제가 본 것은 다음과 같은 "간접적"입니다.
export default = () => {
const [sendRequest, setSendRequest] = useState(false);
useEffect(() => {
if(sendRequest){
//send the request
setSendRequest(false);
}
},
[sendRequest]);
return (
<input type="button" disabled={sendRequest} onClick={() => setSendRequest(true)}
);
}
그게 올바른 방법인가요 아니면 다른 패턴이 있나요?
export default () => {
const [isSending, setIsSending] = useState(false)
const sendRequest = useCallback(async () => {
// don't send again while we are sending
if (isSending) return
// update state
setIsSending(true)
// send the actual request
await API.sendRequest()
// once the request is sent, update state again
setIsSending(false)
}, [isSending]) // update the callback if the state changes
return (
<input type="button" disabled={isSending} onClick={sendRequest} />
)
}
클릭 시 요청을 전송하고 전송 중에 버튼을 비활성화할 경우 요약됩니다.
업데이트:
@tkd_aj는 "마운트 해제된 컴포넌트에서 리액트 상태 업데이트를 수행할 수 없습니다.이것은 no-op이지만, 애플리케이션의 메모리 누수를 나타내고 있습니다.수정하려면 useEffect 정리 함수의 모든 구독 및 비동기 작업을 취소하십시오."
실제로 컴포넌트가 마운트 해제되는 동안 요청이 처리되고 있습니다.그런 다음 시도합니다.setIsSending
(setState)를 선택합니다.
export default () => {
const [isSending, setIsSending] = useState(false)
const isMounted = useRef(true)
// set isMounted to false when we unmount the component
useEffect(() => {
return () => {
isMounted.current = false
}
}, [])
const sendRequest = useCallback(async () => {
// don't send again while we are sending
if (isSending) return
// update state
setIsSending(true)
// send the actual request
await API.sendRequest()
// once the request is sent, update state again
if (isMounted.current) // only update if we are still mounted
setIsSending(false)
}, [isSending]) // update the callback if the state changes
return (
<input type="button" disabled={isSending} onClick={sendRequest} />
)
}
버튼을 클릭했을 때 요청을 보내는 효과는 필요하지 않습니다. 대신 필요한 것은 단지 다음을 사용하여 최적화할 수 있는 핸들러 방식입니다.useCallback
방법
const App = (props) => {
//define you app state here
const fetchRequest = useCallback(() => {
// Api request here
}, [add dependent variables here]);
return (
<input type="button" disabled={sendRequest} onClick={fetchRequest}
);
}
변수를 사용한 추적 요청useEffect
useEffect를 사용하여 상태를 api 호출로 설정할 수 있기 때문에 올바른 패턴은 아니지만 다른 변경으로 인해 추가 렌더가 발생하면 요청이 루프 상태가 됩니다.
기능 프로그래밍에서는 비동기 함수를 부작용으로 간주해야 합니다.
부작용을 다룰 때는 부작용을 시작하는 논리와 부작용 결과의 논리를 분리해야 합니다(rex saga와 유사).
기본적으로 버튼의 책임은 부작용의 유발일 뿐이고, 부작용의 책임은 돔의 갱신일 뿐입니다.
또한 리액션은 컴포넌트를 취급하기 때문에 컴포넌트가 아직 마운트되지 않았는지 확인해야 합니다.setState
또는 매회await
이것은 당신의 취향에 따라 다릅니다.
이 문제를 해결하기 위해 우리는 커스텀 훅을 만들 수 있다.useIsMounted
이 훅을 사용하면 컴포넌트가 아직 장착되어 있는지 쉽게 확인할 수 있습니다.
/**
* check if the component still mounted
*/
export const useIsMounted = () => {
const mountedRef = useRef(false);
const isMounted = useCallback(() => mountedRef.current, []);
useEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
};
});
return isMounted;
};
그러면 코드는 다음과 같습니다.
export const MyComponent = ()=> {
const isMounted = useIsMounted();
const [isDoMyAsyncThing, setIsDoMyAsyncThing] = useState(false);
// do my async thing
const doMyAsyncThing = useCallback(async () => {
// do my stuff
},[])
/**
* do my async thing effect
*/
useEffect(() => {
if (isDoMyAsyncThing) {
const effect = async () => {
await doMyAsyncThing();
if (!isMounted()) return;
setIsDoMyAsyncThing(false);
};
effect();
}
}, [isDoMyAsyncThing, isMounted, doMyAsyncThing]);
return (
<div>
<button disabled={isDoMyAsyncThing} onClick={()=> setIsDoMyAsyncThing(true)}>
Do My Thing {isDoMyAsyncThing && "Loading..."}
</button>;
</div>
)
}
주의: 부작용의 논리와 효과를 유발하는 논리를 분리하는 것이 항상 좋습니다.useEffect
)
갱신:
위의 모든 복잡함을 단순히 라이브러리에서만 사용하는 것이 아니라 훨씬 깨끗하고 간단합니다.
예:
import {useAsyncFn} from 'react-use';
const Demo = ({url}) => {
const [state, doFetch] = useAsyncFn(async () => {
const response = await fetch(url);
const result = await response.text();
return result
}, [url]);
return (
<div>
{state.loading
? <div>Loading...</div>
: state.error
? <div>Error: {state.error.message}</div>
: <div>Value: {state.value}</div>
}
<button onClick={() => doFetch()}>Start loading</button>
</div>
);
};
질문에서처럼 일부 상태 변경의 결과로 데이터를 가져올 수 있지만 클래스 구성 요소에서 익숙한 것처럼 클릭 핸들러에서 직접 데이터를 가져올 수도 있습니다.
예
const { useState } = React;
function getData() {
return new Promise(resolve => setTimeout(() => resolve(Math.random()), 1000))
}
function App() {
const [data, setData] = useState(0)
function onClick() {
getData().then(setData)
}
return (
<div>
<button onClick={onClick}>Get data</button>
<div>{data}</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
그대로 할 수 , 부울을 ""로 할 수 .true
다시 '', '다시', '다시'로 설정해 주세요.false
:
const [requestSent, setRequestSent] = useState(false);
const sendRequest = () => {
setRequestSent(true);
fetch().then(() => setRequestSent(false));
};
훅을 수 .useApi
를 반환한다.execute
되면 api가 으로 일부 api를 api를 합니다).onClick
를 참조해 주세요.
useApi
삭제:
export type ApiMethod = "GET" | "POST";
export type ApiState = "idle" | "loading" | "done";
const fetcher = async (
url: string,
method: ApiMethod,
payload?: string
): Promise<any> => {
const requestHeaders = new Headers();
requestHeaders.set("Content-Type", "application/json");
console.log("fetching data...");
const res = await fetch(url, {
body: payload ? JSON.stringify(payload) : undefined,
headers: requestHeaders,
method,
});
const resobj = await res.json();
return resobj;
};
export function useApi(
url: string,
method: ApiMethod,
payload?: any
): {
apiState: ApiState;
data: unknown;
execute: () => void;
} {
const [apiState, setApiState] = useState<ApiState>("idle");
const [data, setData] = useState<unknown>(null);
const [toCallApi, setApiExecution] = useState(false);
const execute = () => {
console.log("executing now");
setApiExecution(true);
};
const fetchApi = useCallback(() => {
console.log("fetchApi called");
fetcher(url, method, payload)
.then((res) => {
const data = res.data;
setData({ ...data });
return;
})
.catch((e: Error) => {
setData(null);
console.log(e.message);
})
.finally(() => {
setApiState("done");
});
}, [method, payload, url]);
// call api
useEffect(() => {
if (toCallApi && apiState === "idle") {
console.log("calling api");
setApiState("loading");
fetchApi();
}
}, [apiState, fetchApi, toCallApi]);
return {
apiState,
data,
execute,
};
}
를 사용합니다.useApi
「 」 「 」:
const SomeComponent = () =>{
const { apiState, data, execute } = useApi(
"api/url",
"POST",
{
foo: "bar",
}
);
}
if (apiState == "done") {
console.log("execution complete",data);
}
return (
<button
onClick={() => {
execute();
}}>
Click me
</button>
);
이를 위해 ReactJs에서 콜백훅을 사용할 수 있습니다.useEffect를 사용하여 API 호출을 하도록 상태를 설정할 수 있지만 다른 변경으로 인해 추가 렌더가 발생하면 요청이 루프 상태가 되기 때문에 useEffect는 올바른 패턴이 아닙니다.
<const Component= (props) => {
//define you app state here
const getRequest = useCallback(() => {
// Api request here
}, [dependency]);
return (
<input type="button" disabled={sendRequest} onClick={getRequest}
);
}
제 대답은 간단합니다.useState hook을 사용하는 동안 javascript를 false로 설정하면 값을 전달할 수 없습니다.이 값은 true로 설정되면 받아들여집니다.따라서 usestate에서 false를 사용하는 경우 if 조건을 사용하여 함수를 정의해야 합니다.
언급URL : https://stackoverflow.com/questions/55647287/how-to-send-request-on-click-react-hooks-way
'programing' 카테고리의 다른 글
성공적인 약속 해결에서 외부 변수에 값 할당 (0) | 2023.03.31 |
---|---|
SpringBoot - jar 파일 만들기 - META-INF/spring.factories에 자동 구성 클래스가 없습니다. (0) | 2023.03.31 |
사양에서 JSON 데이터를 설명하는 방법은 무엇입니까? (0) | 2023.03.31 |
부호화되지 않는 이유단일 따옴표/부호를 인코딩하는 URIC 컴포넌트 (0) | 2023.03.31 |
React의 useState 훅을 사용할 때 nullable 상태를 입력하는 올바른 방법 (0) | 2023.03.31 |