Specifi c Вопросы об использованииReducer + Context
Здравствуйте,
Я практикую различные способы передачи данных в React, однако есть некоторые вещи, которые все еще уклоняются от меня даже после часы чистящих примеров и документации. Рассмотрим следующие вопросы в контексте следующего кода (очень маленькое приложение для песочницы, с которым я учусь):
0) Из того, что я понимаю, мне нужен доступ к методу отправки, чтобы обновить GlobalContext через редуктор в context.tsx. Кроме того, я должен иметь возможность доступа к тому же методу диспетчеризации в любом компоненте через метод useContext. Я просто не знаю, как добраться до метода отправки. от компонента, который импортирует GlobalContext. Когда я пытаюсь (как видно из header.tsx), возникает ошибка, которая говорит: «Диспетчер свойств не существует для типа« IGlobalState »». IGlobalState - это тип самого объекта состояния (который находится в context.tsx), а не возвращаемый результат createContext, но эта ошибка, кажется, считает иначе? Не уверен, что здесь не так.
1) В context.tsx я заставил VSCode заставить typecast {state, dispatch} к любому, так как передавал их в виде {} в значение prop GlobalContext.Provider не работает по какой-то причине? Каждый учебник и пример онлайн для реакции / ts не имеют этого обходного пути. Почему не работает так, как кажется, так легко для всех? Использование любого типа побеждает цель машинописи ...
2) В loader.tsx я точно понимаю, как используется useContext; это позволяет мне получить доступ к свойствам глобального состояния, например, с помощью синтаксиса «globalContext.isLoading». Однако в примерах , таких как этот , кажется, что они просто извлекают метод отправки прямо из возвращаемого значения useContext, что для меня не имеет смысла. Не будет ли useContext просто возвращать текущее состояние в форме объекта? Вот специфика c, найденная в ссылке выше, о которой я говорю:
import { GlobalContext } from "Components/Context"; // Assume this points to context.tsx
const ExampleComponent = () => {
const globalState = useContext(GlobalContext);
const { dispatch } = globalState;
dispatch({ type: '' }) // Empty example
};
Вы можете видеть, что в заголовке я то же самое. js, но это не сработало , Так как именно это работает и как это должно работать? Я изо всех сил пытался понять, как автор статьи смог получить доступ к функции отправки с этими строками кода. Даже с той же самой установкой это все еще выдает ошибку, которую я понимаю, но я не понимаю, почему я получаю это (см. Questino 0).
Из того, что я понимаю, у меня должен быть доступ к методу отправки так как я завернул все приложение в GlobalContext.Provider в root index.tsx. Я также предположительно передал в состоянии и отправил как объект в реквизиты значения в GlobalStateProvider, хотя это был хакерский способ, которого я не понимаю (см. Вопрос № 1 выше).
Я уверен, что ответ не далеко, но я был бы признателен любому, кто мог бы просветить меня! СПАСИБО за любую помощь, React + Typescript так здорово! Я до сих пор очень люблю опыт разработки / обучения. Вот код приложения:
index.tsx
import React from "react";
import * as ReactDOM from "react-dom";
import { GlobalStateProvider } from "Components/Context";
import { App } from "Components/App";
const Index = () => {
return (
<GlobalStateProvider>
<App />
</GlobalStateProvider>
);
};
ReactDOM.render(<Index />, document.getElementById("root"));
app.tsx
import React from "react";
import { Loader } from "Components/Loader";
import { Header } from "Components/Header";
import "Assets/styles.scss";
export const App = () => {
return(
<div className="app">
<Loader />
<Header />
</div>
);
};
header.tsx
import React, { useContext } from "react";
import { globalActions, GlobalContext } from "Components/Context";
import * as API from "Components/API";
import $ from "jquery";
export const Header = () => {
const globalState = useContext(GlobalContext);
const { dispatch } = globalState; // <-- QUESTION_0
const handleKeyPress = async (event: React.KeyboardEvent<HTMLDivElement>) => {
const searchbarInput: JQuery<HTMLElement> = $("input[name='searchbarInput']");
const header: JQuery<HTMLElement> = $(".header");
if (
searchbarInput.val() &&
(header.is(":hover") || searchbarInput.is(":focus")) &&
event.key === "Enter"
) {
searchbarInput.blur();
dispatch({ type: globalActions.load });
// DO STUFF HERE...
}
};
return(
<div className="header">
<div className="searchbar">
<input className="input" name="searchbarInput" onKeyPress={handleKeyPress} placeholder="Search..." type="text" />
<svg>
... // searchbar icon
</svg>
</div>
</div>
);
};
context.tsx
import React, { createContext, useEffect, useReducer } from "react";
interface IGlobalActions {
type: string;
payload?: Array<string> | object | string;
};
interface IGlobalState {
isLoading: boolean;
};
const globalActions = {
load: "START_LOADING",
};
const initialState: IGlobalState = {
isLoading: false,
};
const GlobalContext = createContext<IGlobalState>(initialState);
const { Provider } = GlobalContext;
const reducer = (state: IGlobalState, action: IGlobalActions) => {
switch(action.type) {
case globalActions.load:
return { isLoading: true };
default:
throw new Error("Invalid action type (StateProvider)");
};
};
const GlobalStateProvider = ({ children }: any) => {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
// Trigger loading animation
if (state.isLoading) {
setTimeout(() => {
dispatch({
type: globalActions.load
});
}, 2000)
}
},
[state.isLoading]);
return (
<Provider value={{ state, dispatch } as any}> // <-- QUESTION_1
{children}
</Provider>
);
};
export { globalActions, GlobalContext, GlobalStateProvider };
loader.tsx
import React, { useContext } from "react";
import * as classnames from "classnames";
import { GlobalContext } from "Components/Context";
export const Loader = () => {
const globalContext = useContext(GlobalContext);
const classNames = classnames({"loader": true}, {"is-loading": globalContext.isLoading});
const loadingAnimation = "https://link/to/loading/animation";
return (
<div className={classNames} >
<img className="image" src={loadingAnimation} alt="Loading..." />
</div>
);
};