Я пытаюсь практиковаться в использовании крючков, и я не могу обдумать это.
У меня есть один компонент MessageBoard, который считывает данные из состояния, которое просто отображает простой список сообщений.
Я передаю dispatch и state через createContext, чтобы дочерние компоненты могли их использовать, что, в свою очередь, использует useContext в дочерних компонентах для чтения значения.
Когда страница обновляется, я ожидаю увидеть начальный пользовательский интерфейс, но он не может отобразить, что значение в контексте не определено. Я уже предоставил начальное состояние редюсеру при его инициализации.
App.js
import React from "react";
import MessageBoard from "./MessageBoard";
import MessagesContext from "../context/MessagesContext";
function App() {
return (
<div>
<MessagesContext>
<h2>Reaction</h2>
<hr />
<MessageBoard />
</MessagesContext>
</div>
);
}
export default App;
MessageBoard.js
import React, { useContext } from "react";
import MessagesContext from "../context/MessagesContext";
function MessageBoard(props) {
const { state } = useContext(MessagesContext);
return (
<div>
{state.messages.map(message => {
return (
<div key = {message.id}>
<h4>{new Date(message.timestamp).toLocaleDateString()}</h4>
<p>{message.text}</p>
<hr />
</div>
);
})}
</div>
);
}
export default MessageBoard;
СообщенияContext.js
import React, { createContext, useReducer } from "react";
import reducer, { initialState } from "../state/reducer";
export default function MessagesContext(props) {
const Context = createContext(null);
const [state, dispatch] = useReducer(reducer, initialState);
return (
<Context.Provider
value = {{
dispatch,
state
}}
>
{props.children}
</Context.Provider>
);
}
Сломанный пример — https://codesandbox.io/s/black-dust-13kj2
Вместо этого, если я немного изменю файл MessagesContext и вместо этого Provider будет напрямую внедрен в App, он будет работать, как и ожидалось. Хотите знать, что я неправильно понял здесь и что может происходить?
СообщенияContext.js
import { createContext } from "react";
export default createContext(null);
App.js
import React, { useReducer } from "react";
import reducer, { initialState } from "../state/reducer";
import PublishMessage from "./PublishMessage";
import MessageBoard from "./MessageBoard";
import MessagesContext from "../context/MessagesContext";
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<MessagesContext.Provider
value = {{
dispatch,
state
}}
>
<h2>Reaction</h2>
<hr />
<PublishMessage />
<hr />
<MessageBoard />
</MessagesContext.Provider>
</div>
);
}
export default App;
Рабочий пример — https://codesandbox.io/s/mystifying-meitner-vzhok



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


useContext принимает объект контекста (значение, возвращаемое из React.createContext) и возвращает текущее значение контекста для этого контекста.
const MyContext = createContext(null);
const value = useContext(MyContext);
// MessagesContext Not a contex object.
const { state } = useContext(MessagesContext);
В первом примере:
// export the context.
export const Context = createContext(null);
export default function MessagesContext(props) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<Context.Provider
value = {{
dispatch,
state
}}
>
{props.children}
</Context.Provider>
);
}
а затем используйте его:
import { Context } from '../context/MessagesContext';
function MessageBoard() {
const { state } = useContext(Context);
...
}
Рабочий сломанный пример:
Спасибо за ответ. Похоже, это то, что я неправильно понял. В этом сценарии я использовал компонент, а не объект контекста. Кроме того, поскольку createContext был определен внутри компонента, он также создавал новый объект контекста при рендеринге.
О, просмотрел код (не запускал песочницы) и полностью пропустил
useContext(MessageContext)(MessageContextна самом деле не является контекстом!). Хорошее место.