Почему я не могу использовать useContext здесь?
Суть моего вопроса заключается в том, чтобы узнать почему внутри Todos.tsx я могу использовать useContext, а внутри TodosPage.tsx не могу. Выбрасывает 2 ошибки. Если что, то я работаю на 18 версии и использую бутстрап.
Вот необходимые файлы:
App.tsx
import React from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import Alert from './components/Alert'
import Header from './components/Header'
import AlertState from './context/alert/AlertState'
import FirebaseState from './context/firebase/FirebaseState'
import { routes } from './routes/routes'
export default function App() {
return (
<AlertState>
<BrowserRouter>
<Header/>
<div className={'container pt-4'}>
<Alert/>
<FirebaseState>
<Routes>
{
routes.map((route) =>
<Route path={route.path} element={route.elem} key={route.path}></Route>
)
}
</Routes>
</FirebaseState>
</div>
</BrowserRouter>
</AlertState>
)
}
TodosPage.tsx
import React from 'react'
import Form from '../components/Form';
import Todos from '../components/Todos';
import { FirebaseContext } from '../context/firebase/firebaseContext';
import FirebaseState from '../context/firebase/FirebaseState';
const TodosPage = () => {
//! ВОТ ИЗ-ЗА ЧЕГО ВОЗНИКАЕТ ОШИБКА
// const {firebaseState} = React.useContext(FirebaseContext)
// console.log(firebaseState)
return (
<div className='container'>
<h1 className='display-4 fw-bold text-decoration-underline'>Main</h1>
<Form/>
<hr/>
<p className='font-monospace fw-700 fs-14 text-center mt-5 text-decoration-underline'>Your Books</p>
<Todos/>
</div>
)
}
export default TodosPage;
Todos.tsx (Здесь всё работает нормально)
import React from 'react'
import { FirebaseContext } from '../context/firebase/firebaseContext';
import { ITodo } from '../types/ITodo'
const Todos = () => {
//! ЗДЕСЬ ПРОБЛУЕМ НЕТ, ЛОГИ ПОКАЗЫВАЮТ ОТВЕТ
const {firebaseState} = React.useContext(FirebaseContext);
console.log(firebaseState);
return (
<ol className="list-group list-group-numbered mb-5">
{/* {
todos.map(todo =>
<li className="list-group-item d-flex justify-content-between align-items-start">
<div className="ms-2 me-auto">
<div className="fw-bold">{todo.title} <span className='fw-light fs-10 font-monospace'> - {todo.time} min.</span></div>
{todo.additional}
</div>
<div className='d-flex flex-column'>
<div className='d-flex justify-content-end mb-2'>
<span className="badge bg-primary rounded-pill">{todo.potency}</span>
</div>
<button type="button" className="btn btn-danger">×</button>
</div>
</li>
)
} */}
</ol>
)
}
export default Todos
firebaseContext.ts
import React from 'react'
import { IFirebase } from './firebaseTypes';
interface IFirebaseContext {
showLoader: () => void;
addTodo: () => Promise<void>;
fetchTodos: () => Promise<void>;
removeTodo: (id: number) => Promise<void>;
firebaseState: IFirebase;
}
export const FirebaseContext = React.createContext<IFirebaseContext>({} as IFirebaseContext);
firebaseReducer.ts
import { IFirebase, IFirebaseAction } from "./firebaseTypes"
export const firebaseReducer = (state: IFirebase, action: IFirebaseAction): IFirebase => {
switch(action.type) {
case 'SHOW_LOADER':
return {...state, loading: true}
case 'ADD_TODO':
return {...state, todos: [...state.todos, ...(action.payload ? action.payload.todos : [])]}
case 'DELETE_NOTE':
return {...state, todos: state.todos.filter(todo => todo.id !== action.id)}
case 'FETCH_NOTES':
return {...state, todos: action.payload?.todos!}
default:
return state
}
}
firebaseTypes.ts
import { ITodo } from "../../types/ITodo";
export type TFirebaseActionType = 'HIDE_ALERT' | 'SHOW_ALERT' | 'SHOW_LOADER' | 'ADD_TODO' | 'FETCH_NOTES' | 'DELETE_NOTE';
export interface IFirebase {
todos: ITodo[];
loading: boolean;
}
export interface IFirebaseAction {
type: TFirebaseActionType;
payload?: IFirebase;
id?: number;
}
FireabseState.tsx (Последнее)
import axios from 'axios';
import React from 'react'
import { ITodo } from '../../types/ITodo';
import { FirebaseContext } from './firebaseContext';
import { firebaseReducer } from './firebaseReducer';
interface FirebaseStateProps {
children: React.ReactNode | React.ReactChild;
}
const URL: string = process.env.REACT_APP_DB_URL!;
const FirebaseState: React.FC<FirebaseStateProps> = ({children}) => {
const [state, dispatch] = React.useReducer(firebaseReducer, {todos: [], loading: false})
const showLoader = () => {
dispatch({type: 'SHOW_LOADER', payload: {...state}})
}
const fetchTodos = async () => {
showLoader();
const result = await axios.get(`${URL}/todos.json`);
console.log('fetchNotes', result.data);
dispatch({type: 'FETCH_NOTES', payload: {...state, todos: result.data}})
}
const addTodo = async () => {
const todo: ITodo = {
id: Date.now(),
completed: false,
additional: 'New todo',
potency: 3,
time: 25,
title: 'Fushhh'
}
const result = await axios.post(`${URL}/todos.json`, todo);
console.log('addTodo', result.data);
dispatch({type: 'DELETE_NOTE', payload: {...state, todos: [...state.todos, result.data]}})
}
const removeTodo = async (id: number) => {
await axios.delete(`${URL}/notes/${id}.json`);
dispatch({type: 'DELETE_NOTE', payload: {...state}, id})
}
return (
<FirebaseContext.Provider value={{firebaseState: state, showLoader, addTodo, removeTodo, fetchTodos}}>
{children}
</FirebaseContext.Provider>
)
}
export default FirebaseState
Здесь firebase не имеет прямо принципиального влияния, т.к. я пробовал и без него так делать - безуспешно. Я понимаю, что вопрос довольно большой, но я прошу мне помочь, потому что я и сам потратил много времени как решить этот вопрос. Мне кажется, что другим новичкам, как и мне, такой вопрос пойдет только на пользу. Если потребуется доп. информация - пишите.
