Я пытаюсь реализовать как Redux, так и React-Router в проекте блога React, в котором я получаю данные из API и сохраняю их в Redux, однако они не отображаются и ошибок не возникает.
Я попробовал следующий код в своем App.jsx
const getRouter = (store) => {
return (
createBrowserRouter(
createRoutesFromElements(
<Route path = "/" element = {<Layout />}>
<Route
index
element = {<PostList />}
errorElement = {<Error />}
loader = {(arg) => {
arg.post = store.getState().posts
}}
/>
<Route path='/posts' element = {<PostForm />}>
<Route />
</Route>
<Route path = "*" element = {<NotFound />} />
</Route>
)
)
)
}
export default function App() {
<Provider store = {store}>
<RouterProvider router = {getRouter(store)} />
</Provider>
}
🤔 А знаете ли вы, что...
JavaScript позволяет создавать собственные серверные приложения с использованием платформы Node.js.
Функция загрузчика маршрута принимает один объект аргумента со свойствами params
и request
. arg.post
не определено.
Компонент App
также должен вернуть JSX, который он собирается отобразить.
Если вам нужно получить доступ к контексту хранилища Redux в загрузчике маршрутов, я бы предложил просто импортировать store
и получить доступ непосредственно в функции загрузчика вместо закрытия экземпляра хранилища в маршрутизаторе. Проблема с имеющимся у вас кодом заключается в том, что он будет создавать новый маршрутизатор каждый раз, когда обновляется магазин и выполняется повторная отрисовка компонента Provider
.
Пример:
const router = createBrowserRouter(
createRoutesFromElements(
<Route element = {<Layout />}>
<Route
path = "/"
element = {<PostList />}
errorElement = {<Error />}
loader = {({ params, request }) => {
const { posts } = store.getState();
// return some value to `PostList` component
}}
/>
<Route path='/posts' element = {<PostForm />}>
...
</Route>
<Route path = "*" element = {<NotFound />} />
</Route>
)
)
export default function App() {
return (
<Provider store = {store}>
<RouterProvider router = {router} />
</Provider>
);
}
Если вы действительно хотите по-прежнему использовать функцию для получения маршрутизатора, то хотя бы запомните маршрутизатор, чтобы он предоставлялся как стабильная ссылка и не создавался заново каждый раз при App
или Provider
повторном рендеринге.
export default function App() {
const router = React.useMemo(() => getRouter(store), [store]);
return (
<Provider store = {store}>
<RouterProvider router = {router} />
</Provider>
);
}
Если вам не нужно использовать загрузчик маршрутов, кроме как для доступа и возврата значения хранилища, есть лучшие альтернативы. Вы можете просто использовать хуки useDispatch и useSelector, экспортированные из react-redux
, в компонентах, которым необходимо подписаться на обновления состояния.
Пример:
...
import { useSelector } from 'react-redux';
...
const PostList = () => {
const posts = useSelector(state => state.posts);
...
};
const router = createBrowserRouter(
createRoutesFromElements(
<Route element = {<Layout />}>
<Route
path = "/"
element = {<PostList />}
errorElement = {<Error />}
/>
<Route path='/posts' element = {<PostForm />}>
...
</Route>
<Route path = "*" element = {<NotFound />} />
</Route>
)
)
export default function App() {
return (
<Provider store = {store}>
<RouterProvider router = {router} />
</Provider>
);
}
Основное преимущество использования перехватчика useSelector
заключается в том, что это подписка: при обновлении выбранного состояния подписанные компоненты будут запускаться для повторной визуализации с текущим значением состояния. Это не тот случай, когда используется store.getState
, он получает текущее значение только один раз, в момент вызова getState
, и не подписывается на будущие изменения.