Redux & React-router : Provider bug - javascript

I'm starting new app using ReactJS. All the web env is quite new for me.
Anyway, I created an simple App, using react-router. Works perfectly :).
I tried to add Redux, and ... fail. I have no idea how use React-redux AND react-router.
Here's my input JS : index.js
class App extends React.Component{
render(){
return(
<div>
{routes}
</div>
);
}
}
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('app')
);
Here's my route.js
export default (
<Router history={hashHistory}>
<Route path='/' component={Main}>
<IndexRoute component={Home} />
<Route path='playerOne' header="PlayerOne" component={PromptContainer} />
<Route path='playerTwo/:playerOne' header="PlayerTwo" component={PromptContainer} />
<Route path='battle' component={ConfirmBattleContainer} />
<Route path='results' component={ResultsContainer} />
<Route path='maninthemiddle' component={ManinthemiddleContainer} />
<Route path='button' component={ButtonContainer} />
</Route>
</Router>
);
and ofc my reducer.js
import reducer from './reducer.js'
import { createStore } from 'redux';
const store = createStore(reducer);
export default store;
And this is my error.
Uncaught Error: React.Children.only expected to receive a single React element > child
and my warning :
Warning: Failed prop type: Invalid prop children of type array supplied > > to Provider, expected a single ReactElement.
I know that Provider have to be on "top" of the app, but it's exactly what I did. I'm lost :(
Thanks for your helps guys.

You need to remove the whitespace around <App />. This:
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('app')
);
should be:
ReactDOM.render(
<Provider store={store}><App /></Provider>,
document.getElementById('app')
);
the spaces in there are being treated as text nodes, i.e. additional children.

Related

React Recoil persist state between routes

I want to use Recoil to share a state between to React Router Routes.
My setup looks something like this:
ReactDOM.render(
<React.StrictMode>
<RecoilRoot>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/checkin" element={<Checkin />} />
<Route path="/checkin/confirm" element={<ConfirmCheckin />} />
</Routes>
</BrowserRouter>
</RecoilRoot>
</React.StrictMode>,
document.getElementById("root")
);
My atom setup looks like this:
const checkinItemsState = atom<InventoryItem[]>({
key: "checkinItemsState",
default: [],
});
In both components i use useRecoilState(checkinItemsState)
Now when i open localhost:3000/checkin it shows my state and i can modify it. When i then navigate to localhost:3000/checkin/confirm my state is just an empty array.
What am I missing here? is there something i misunderstand?
So fare I've tried to wrap my Routes with a component like:
const Index: React.FC<{ children: ReactNode }> = ({ children }) => {
useRecoilState(checkinItemsState);
return (
<>
<span>Hello World</span>
{children}
</>
);
};
I guessed maybe it was because the state was nowhere referenced when moving between urls. This does not work.
Any help would be appreciated.

Why is Redux Provider tag breaking the entire App

I am trying to integrate React Toolkit app into a project.
However, I am getting the following error.
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
store.js
import { configureStore } from "#reduxjs/toolkit";
export const store = configureStore({
reducer: {},
})
index.js
ReactDOM.render(
<EventTemplateProvider>
<AuthState>
<SetStripeLayout>
<EventState>
<TicketState>
<AlertState>
<Provider store={store}> <===== Provider
<BrowserRouter>
<Suspense fallback={<Spinner />}>
<Switch>
<Route
exact
path="/"
render={(props) => <App {...props} />}
/>
<PrivateRoute
path="/dashboard"
render={(props) => <Dashboard {...props} />}
/>
<PrivateRoute
path="/template"
render={(props) => <EventTemplate {...props} />}
/>
<PrivateRoute
path="/events"
render={(props) => <Events {...props} />}
/>
<AdminRoute
path="/admin"
render={(props) => <AdminLayout {...props} />}
/>
<Route
path="/readmore/:id"
render={(props) => <VirtualEventReadMore {...props} />}
/>
<Route
path="/*"
render={(props) => <Error404 {...props} />}
/>
<Redirect from="/" to="/" />
</Switch>
</Suspense>
</BrowserRouter>
</Provider>
</AlertState>
</TicketState>
</EventState>
</SetStripeLayout>
</AuthState>
</EventTemplateProvider>,
document.getElementById("root")
);
I did not start coding anything for redux.
and when I remove Provider tag, the app works.
Can anyone tell me why it is breaking apart?
thank you in advance.
modified index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './store';
ReactDOM.render(
<Provider store={store}>
<h1>Hello </h1>
</Provider>
, document.getElementById('root'));
Check Pacakage.json file if the modules are installed or not.Make sure that you have installed these pacakges:-
npm i #reduxjs/toolkit
npm i react-redux

How to separate routes from index.js in React

I am trying to separate my routes to a separate file using the following code in index.js:
import routes from './routes';
ReactDOM.render(
<Provider store={store}>
<Router routes={routes}/>
</Provider>
, document.getElementById('root')
);
my routes.js looks like this:
export default (
<Switch>
<Route exact path="/" component={AppComponent}/>
<Route exact path="/products" component={ProductContainer}/>
<Route path="/products/:productId" component={AddProductComponent}/>
</Switch>
);
For some reason my page appears blank with this code.
It works perfectly fine if I just wrap all routes inside index.js like this:
ReactDOM.render(
<Provider store={store}>
<Router>
<Switch>
<Route exact path="/" component={AppComponent}/>
<Route exact path="/products" component={ProductContainer}/>
<Route path="/products/:productId" component={AddProductComponent}/>
</Switch>
</Router>
</Provider>
, document.getElementById('root')
);
I would keep it like this, but I would also want to separate into a single file route handling.
Router is just a React component that allows for children prop. Render your routes as a component:
import Routes from './routes';
ReactDOM.render(
<Provider store={store}>
<Router>
<Routes />
</Router>
</Provider>
, document.getElementById('root')
);
Here a sample working codesandbox to play: https://codesandbox.io/s/ywvn59y7rj
More detailed answer, changing routes.js to
class Routes extends React.Component {
render() {
return (
<Switch>
<Route exact path="/" component={AppComponent}/>
<Route exact path="/products" component={ProductContainer}/>
<Route path="/products/:productId" component={AddProductComponent}/>
</Switch>
)
}
}
export default Routes;
and changing index.js to:
ReactDOM.render(
<Provider store={store}>
<Router>
<Routes/>
</Router>
</Provider>
, document.getElementById('root')
);
worked perfectly fine. I hope this would help anybody
Another option wich is easier to maintain is storing routes as JSON like objects in an array and then loop over them.
routes.js
import AppComponent from 'xxx'
export default const routes = [
{
path: '/',
component: AppComponent,
exact: true
}
// and so on
]
index.js
import routes from './routes';
ReactDOM.render(
<Provider store={store}>
<Router>
{routes.map({path, component, exact} => (
<Route exact={exact} path={path} component={component}/>
)}
</Router>
</Provider>
, document.getElementById('root')
);

react-router-dom on the server

I did find out that I can't use when I'm rendering my app on the server. I would like to wrap my App in specified router depending on the situation - BrowserRouter on the CLient side and StaticRouter on server side. My App looks like this:
imports......
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<BrowserRouter>
<div>
<Menu />
<main>
<Switch>
<Route exact path="/about" component = {About} />
<Route exact path="/admin" component = {BooksForm} />
<Route exact path="/cart" component = {Cart} />
<Route exact path="/" component = {BookList} />
</Switch>
<Footer />
</main>
</div>
</BrowserRouter>
);
}
componentDidMount(){
this.props.getCart();
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
getCart
}, dispatch)
}
export default connect(null, mapDispatchToProps)(App);
I tried to move my BrowserRouter ou of this component so my index.js would look like this:
imports....
const renderApp = () => (
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>
)
const root = document.getElementById('app')
render(renderApp(), root)
So I would get ability to wrap my app in different routers. The problem is when I moved BrowserRouter out of my App component it stopped working. Clicking on links just does not work anymore. The url is changing but my app isn't rendering differnet components. How can I move router out of this component?
On the server, you'll wrap your app similar to this:
const routerContext = {};
const appComponent = (
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext}>
<App />
</StaticRouter>
</Provider>
);
Where you pass react-router the location (from the url) as well as a context object.
The client side is like your example:
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>

Error: v(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object

I am new to react and react-router. I am migrating from react-router v2.8.1 to v4.1.1. I am getting this error in the following code. Please help. Thanks in advance.
const reactRouterDom = require<any>('react-router-dom');
let {BrowserRouter, Route} = reactRouterDom;
ReactDOM.render(
<Provider store={store}>
<BrowserRouter onUpdate={scrollToTop}>
<Route path="/" component={App} />
</BrowserRouter>
</Provider>, document.getElementById('app')
);

Categories

Resources