reducers: {
addArticle(state, action) {
state.post = state.post.push(action.payload)
}
}
props: ButtonProps | AnchorProps
. Внутри компонента логика бы осталась прежней, но вот что бы произошло снаружи:<Button onClick={e => {}} />
// где MouseEvent происходит то ли для HTMLButtonElement, то ли для HTMLAnchorElement
// и нам нужно будет явно это все дело проверить + атрибут type ничего нам не подскажет
// поскольку у ссылок тоже есть атрибут type и для компонента он просто станет типа string... ужас
href
это 100% кнопка! onClick
будет относится к HTMLButtonElement
, type
будет подсказывать только типы, которые доступны для кнопки. В противном случае - это 100% ссылка, ведь я передал href
.ref
? Затем же, зачем и все остальное. Цель такова, чтобы работая с кнопкой я не должен был зачем-то проверять будет ли событие клика происходит точно на кнопке, а не на ссылке... бред же? ref
- если я не передаю параметр href
, то это бы означало что я не могу передать в этот компонент ref
на ссылку, поскольку компонент работает напрямую с кнопкой. props
компонента, чтобы понять что рендерить - кнопку или ссылку.button
- нам доступны все атрибуты из ButtonProps
.<Button />
href
в виде строки и теперь нам доступны все атрибуты из AnchorProps
- тот же самый onClick
теперь явно взаимодействует с HTMLAnchorElement
.<Button href="/posts" />
ref
:Но это реализация компонента с помощьюFunctionComponent
, но сколько я ни пытался - не получается это переписать наForwardRefRenderFunction
, чтобы передаваемые ref зависели отProps
ButtonProps
, а есть AnchorProps
. Первый нужен для кнопки, а второй для ссылки. Перегрузка решает вопрос того, как этот компонент доступен снаружи:<Button /> // это кнопка
<Button type="button" /> // атрибут type автоматически подскажет мне только нужные значения - button/reset/submit
<Button onClick={(e) => {}} /> // MouseEvent будет работать для HTMLButtonElement
<Button href="/" /> // это ссылка
<Button href="/" type="???" /> // это ссылка, но ей я уже не могу перекинуть типы кнопки
<Button href="/" onClick={(e) => {}} /> // MouseEvent будет работать для HTMLAnchorElement
react-query
- очень удобная) isLoading
, isError
, data
и прочее) и вызываю их внутри компонента.function useGetData(...) {
const [ isLoading, setIsLoading ] = React.useState(false)
const [ isError, setIsError ] = React.useState(false)
const [ data, setData ] = React.useState(null)
async function getData() {
try {
setIsLoading(true)
const data = await fetch(...)
setData(data)
} catch (error) {
setIsError(true)
} finally {
setIsLoading(false)
}
}
return {
isLoading,
isError,
data
}
}
const Component = () => {
const {
isLoading,
isError,
getData,
data
} = useGetData()
if (isLoading) return (<div>Loading...</div>)
if (isError) return (<div>Oops...</div>)
if (data) return (<div>{data}</div>)
return (
<button onClick={getData}>
получить данные
</button>
)
}
useEffect
на отлов data
и как только ты их получаешь - диспатчишь куда требуется. А ещё лучше не городить велосипед и использовать react-query
, который позволяет удобно работать с запросами, "оборачивая" их в хуки.AuthManager
, а точнее в хуке useSubscribeToAuthChange
import React from 'react'
import { User, getAuth, onAuthStateChanged } from 'firebase/auth'
import useStoreDispatch from 'hooks/store/useStoreDispatch'
import useStoreSelector from 'hooks/store/useStoreSelector'
import { firebaseApp } from 'utils/configs/FirebaseConfig'
import { userActions } from 'store/slices/UserSlice'
type UseSubscribeToAuthChangeReturn = {
isLoading: boolean
isSuccess: boolean
isError: boolean
error: Error | null
reset: () => void
}
function useSubscribeToAuthChange(): UseSubscribeToAuthChangeReturn {
const userState = useStoreSelector((store) => store.userState)
const dispatch = useStoreDispatch()
const [ isLoading, setIsLoading ] = React.useState<boolean>(true)
const [ isSuccess, setIsSuccess ] = React.useState<boolean>(false)
const [ isError, setIsError ] = React.useState<boolean>(false)
const [ error, setError ] = React.useState<Error | null>(null)
const firebaseAuth = getAuth(firebaseApp)
function reset(): void {
setIsLoading(true)
setIsSuccess(false)
setIsError(false)
setError(null)
}
function authChangeHandler(user: User | null): void {
if (user) {
dispatch(userActions.signIn({
uid: user.uid,
email: user.email,
displayName: user.displayName,
phoneNumber: user.phoneNumber,
photoURL: user.photoURL,
providerId: user.providerId
}))
}
if (!user && userState.isAuthorized) {
dispatch(userActions.signOut())
}
setIsLoading(false)
setIsSuccess(true)
}
function authErrorHandler(error: Error): void {
setIsError(true)
setError(error)
}
React.useEffect(() => {
const unsubscribe = onAuthStateChanged(firebaseAuth, authChangeHandler, authErrorHandler)
return unsubscribe
}, [firebaseAuth]) // eslint-disable-line react-hooks/exhaustive-deps
return {
isLoading,
isSuccess,
isError,
error,
reset
}
}
export default useSubscribeToAuthChange
React
для начинающих. Учитывая то, что Вам в любом случае нужно будет разобраться с тем, как работает node.js
- это будет определённо полезно) React
в виде подключения его в .html
файлы в виде скриптов - это в любом случае Вам никогда не пригодится и только лишний раз будет запутывать (по крайней мере когда я пытался втянуться в React
у меня было так).React
приложение через:.js
файлы вместе с .jsx
- да, можно, но опять-таки - начните лучше с создание React
приложений через те способы, которые я перечислил выше, а не через обычное подключение через скрипты)) .jsx
React
есть новая документация, где Ваш пример будет выглядеть иначе:import { createRoot } from 'react-dom/client';
// Clear the existing HTML content
document.body.innerHTML = '<div id="app"></div>';
// Render your React component instead
const root = createRoot(document.getElementById('app'));
root.render(<h1>Hello, world</h1>);
https://redux-toolkit.js.org/usage/immer-reducers#...