I'm was making the shopping card Project and I decide to use Contextapi and useReducer for my state management at the start of my project I wrap the App in context Api and it crash my App Here is the Code.
****Main Index *******
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import Context from "./Context";
ReactDOM.render(
<React.StrictMode>
<Context>
<App />
</Context> </React.StrictMode>,
document.getElementById("root")
);
**** Context Api******
import { createContext } from "react";
const Card = createContext();
const Context = ({ childern }) => {
return <Card.Provider>{childern}</Card.Provider>;
};
export default Context;
Just a guess because you didn't provide enough information on the error but you could try moving the context initialization to a separate module and just import it where you need it.
I ran into a strange runtime issue when I initialized it in a UI component.
You need to pass a value prop to context provider without that there is no point of using context API.
As you have mentioned you are using useReducer , an example would be like below to pass the state to the children.
const Context = ({ childern }) => {
const [state,dispatch] = useReducer(reducer,initialState)
return <Card.Provider value={state}>{childern}</Card.Provider>;
};
Related
In my project I have the index.tsx calling the App.tsx that uses a UserProvider and AuthProvider. I received an invalid call error from inside the UserProvider because I'm using the useState hook.
This problem occurs also if I create a custom hook, I can't use any hook inside the custom hook.
This is my index.tsx:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
//import './commons/global.css';
import reportWebVitals from './reportWebVitals';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
reportWebVitals();
This is my App.tsx:
import { useEffect, useState } from 'react';
import { BrowserRouter, useNavigate } from 'react-router-dom';
import {
AuthService,
AuthProvider,
useAuth,
useLogin,
UserProvider,
} from 'reactjs-oauth2-pkce-provider';
import './index.css';
import Routes from './routes';
const authService = new AuthService({...});
const App = () => {
const [user, setUser] = useState({});
const [loading, setLoading] = useState(true);
// for every refresh of the page, check if there is a user in localStorage
useEffect(() => {
const user = localStorage.getItem('user');
if (user) {
setUser(JSON.parse(user));
}
setLoading(false);
}, []);
return (
<UserProvider>
<AuthProvider authService={authService}>
<Routes />
</AuthProvider>
</UserProvider>
);
};
export default App;
This is my UserProvider.tsx:
import React, { ReactElement, useState } from 'react';
import { UserContext } from '#app/application/UserContext';
export const UserProvider = ({ children }: { children: ReactElement }) => {
const [user, setUser] = useState({});
console.log(user);
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
};
There is no function that is calling the hook outside a functional component (there is?)!
A important thing to note is that the UserProvider.tsx is part of a separate package for authentication that I'm building and importing from it with yarn link.
I already tested to install directly from github without success.
I already tested declaring the function with React.FC type but the result is the same.
The understanding that I have from it until now is that the react do not know that the App() function is a functional component and the call for UserProvider is inside a functional component.
I'm expecting that I can use hooks inside the provider, to work useState, useEffect, useNavigate.
The error message is telling you that your error is in fact originating from your Hook call in UserProvider.tsx at line 5.
When you don't import components traditionally as react Components such as
<Component/>
and instead import them as a function such as
return component();
or as in your case, importing them as a wrapper:
<Component>Parent</Component>
Then React hooks won't work.
I would recommend using Redux for logins or the useContext Hook to manage logins if you can't figure out the Traditional React Hooks way of managing this. useContext is also a React hook which would cause the same error if implemented in a similar way, but Redux wouldn't cause you to adhere to any of these strict React rules..
There's a lot of existing Login Templates on Github, including ones with Redux. Implementing Logins is the most boring and tedious process I've dealt with, which can usually take extremely long. Traditionally I use App Skeletons with login capabilities already implemented, and then add all the fun code over, but try the suggestions I mentioned.
The error message that you posted contains three possible reasons for the error. Based on the information that you've provided, reason #3 seems like the most likely culprit.
You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app.
I don't see anywhere in your code, at least not in what you've posted, that you are violating the rules of hooks.
It's what you've said here that jumps out:
A important thing to note is that the UserProvider.tsx is part of a separate package for authentication that I'm building and importing from it with yarn link.
I suspect that your reactjs-oauth2-pkce-provider package is declaring react in the dependencies rather than the peerDependencies. This would cause you to have two copies of react -- one from the package and another from your main app. If these two versions don't match, you could be dealing with reason #1 as well.
The "Duplicate React" section of the docs contains a few checks that you can do to confirm that you do in fact have two copies of React.
If you see more than one React, you’ll need to figure out why this happens and fix your dependency tree. For example, maybe a library you’re using incorrectly specifies react as a dependency (rather than a peer dependency).
Since this is a package that you created and control, you can fix the problem at its root. the solution is to remove react from the dependencies array in your package's package.json and move it to the peerDependencies array instead. You may also need it in the devDependencies. Here is a good example.
okay, so i'm new to the react world, and i was learning about the react useContext, i followed exactly what a tutorial on youtube did, i'm trying to build a little project, i tried following his steps and then i hit an error while trying to use the state i literally want it to be accessible accross my app components, inside my app i've created various componenents and also various responsibility that combines all the reusuable components and do a specific task with it. i'm now trying to access my context from my GETCLICKEDIMAGES file, below are my steps
StateContext.jsx file
import React, { useState, createContext } from "react";
export const StateContext = createContext();
export const StateProvider=(props)=> {
//all the components in this app will share this state.
const [names, setNames] = useState([{ name: "Zucci Daniel! its working" }]);
return (
<StateContext.Provider value={"helo"}>{props.children}</StateContext.Provider>
);
}
App.js
import React, { Component } from "react";
import BigWrapper from "./justComponents/BigWrapper/BigWrapper";
import NavBar from "./justComponents/NavBar/NavBar";
import MainContainer from "./justComponents/MainContainer/MainContainer";
//below are the various responsibilities component
import SEARCHANDDISPLAY from "./Responsibilities/SEARCHANDDISPLAY/SEARCHANDDISPLAY";
import { GETCLICKEDIMAGES } from "./Responsibilities/GETCLICKEDIMAGES/GETCLICKEDIMAGES";
import { StateContext } from "./StateContext/StateContext";
class App extends Component {
render() {
return (
<StateContext>
<BigWrapper>
<NavBar />
<MainContainer>
<SEARCHANDDISPLAY />
<GETCLICKEDIMAGES />
</MainContainer>
</BigWrapper>
</StateContext>
);
}
}
export default App;
GETCLICKEDIMAGE.jsx
import React,{useContext} from "react";
import ClickedImageHolderDiv from "../../justComponents/ClickedImageHolderDiv/ClickedImageHolderDiv";
import Figure from "../../justComponents/Figure/Figure";
//you wanna use the stateContext right? import the context here as so;
import { StateContext } from "../../StateContext/StateContext";
//this is responsible for getting the clicked images and displaying them in full details
/**
a DIV to hold the FIGURE
*/
export const GETCLICKEDIMAGES=()=> {
const value =useContext(StateContext);
return (
<ClickedImageHolderDiv>
<h2>{value}</h2>
<Figure useThisStyle={{ height: "100%" }} />
</ClickedImageHolderDiv>
);
}
i don't know if i'm missing something, or something's changed, pls help.
Import StateProvider in your app.js instead of stateContext
If I'm already using next-auth within my next.js app can I add redux around it inside _app.js somehow?
what i tried is this:
import React from "react"
import { Provider } from 'next-auth/client'
import {Provider as ReduxProvider} from 'react-redux';
import {configureStore} from './store/configureStore';
import '../public/styles.css'
const store = configureStore();
export default function App ({ Component, pageProps }) {
return (
<ReduxProvider store={store}>
<Provider
// next-auth params, etc.
is this correct? does it work this way?
i'll also need to use redux-saga, new to the whole thing so i'm at a setup stage yet
The answer is YES. You can do that. I've tried myself and it works perfectly.
I have the latest version react react#17.0.1 and use the react-player library, import the player, insert it into the layout and get errors:
------- 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
------- VM30105 react-dom.development.js:20085 The above error occurred in the component: at Provider
(webpack-internal:///./node_modules/react-redux/es/components/Provider.js:14:20)
Consider adding an error boundary to your tree to customize error
handling behavior.
------- Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your
application. To fix, cancel all subscriptions and asynchronous tasks
in a useEffect cleanup function.
As soon as I remove the Provider store = {store} /Provider wrapper everything works fine, which may be the problem, also when I try to add functional components I created, the same error occurs.
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { rootReducer } from "../redux/rootReducer.js";
import ReactPlayer from 'react-player'
import { compose, createStore } from "redux";
import { Provider } from "react-redux";
const store = createStore(
rootReducer,
compose(
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
const app = (
<Provider store={store}>
<App />
</Provider>
);
function App() {
return (
<div>
<ReactPlayer url='https://www.youtube.com/watch?v=ysz5S6PUM-U' />
</div>
);
}
export default App;
if (document.getElementById("app")) {
ReactDOM.render(app, document.getElementById("app"));
}
Is there any way to create an action in your MobX store, which pushes your app to a new url using react router v4, e.g. this.props.history.push...
I constantly get a history undefined error, but am unsure how to access the history from my store.
The history push called from the component itself does work though..
many thanks! (this is driving me crazy..)
Since I stumbled across the same issue, I'll share my solution. I just put the RouterStore into its own file in my stores directory, then if I needed access to history or location or whatever, I would import the routing store into the store I was currently working in.
./stores/routing.ts
import { RouterStore } from 'mobx-react-router'
export default new RouterStore()
./stores/other-store.ts
import routing from './routing'
export class OtherStore {
#action
doSomething = () => {
routing.push('/new-route')
}
}
export default new OtherStore()
./index.ts
import { Router } from 'react-router-dom'
import { Provider } from 'mobx-react'
import createBrowserHistory from 'history/createBrowserHistory'
import { syncHistoryWithStore } from 'mobx-react-router'
import otherStore from './stores/other-store'
import routing from './stores/routing'
const browserHistory = createBrowserHistory()
const stores = {
otherStore,
routing,
}
const history = syncHistoryWithStore(browserHistory, routing)
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('root'),
)
You can use mobx-react-router to put react-router in a mobx store and then use it by injecting it in components.
You can also pass the router store as a constructor argument to your other stores that need it. This way you have the router history instance available in your mobx store.
I would like to add a simpler solution that does not require any additional libraries. React Router version is 5.2
Among my stores i've created a HistoryStore.js with the following code:
import { createBrowserHistory } from 'history';
export class HistoryStore {
history = createBrowserHistory();
}
Then I create an instance of it in my contexts.js file but you could do it right away.
export const history = new HistoryStore();
After that you import it in your index.js and pass it as a history prop to the Router.
That's it. Now you could import this store into any other and use it there. When you use useHistory hook in your component it gets this history object, so your history in synchronized.