I recently started building a react app.
I wanted to configure a neo4j database attached to the application. I decided to use the use-neo4j hook. I followed the basic step of creating the driver instance like this:
import React from "react";
import ReactDOM from "react-dom";
import "./css/index.css";
import App from "./js/App";
import Nav from "./js/Nav";
import { Neo4jProvider, createDriver } from "use-neo4j";
const driver = createDriver("neo4j", "localhost", 7687, "lode", "neo4j");
ReactDOM.render(
<React.StrictMode>
<Neo4jProvider driver={driver}>
<Nav />
<App />
</Neo4jProvider>
</React.StrictMode>,
document.getElementById("root")
);
But I ended up having the Invalid Hook Call error.
Except if I remove the Neo4jProvider tags
Seen in this image here
I tried everything I can to fix it, I'm pretty new at React.
I would love someone to help me if they can.
Just like the error says, you can only call hooks inside the body of a functional component. So I would probably create a component that initiates the driver and returns the component that uses it -
import { Neo4jProvider, createDriver } from "use-neo4j";
const NeoProvider = ({ children }) => {
const driver = createDriver("neo4j", "localhost", 7687, "lode", "neo4j");
return (
<Neo4jProvider driver={driver}>
{children}
</Neo4jProvider>
);
}
And then import that at your top level and use that instead of the Neo4jProvider you're importing from the package.
Fixed the issue, I had multiple Reactjs running
Related
I have a project using react-router v6, and I am getting an error stating useNavigate() may be used only in the context of a <Router> component.
For some background, I have two projects that live in the same repo and get built together. We leverage code splitting and import them as needed, not sure if this matters.
Now, I have a setup that is pretty simple:
(in the #dummyInc/components project)
Dummy.tsx
import React from 'react'
export function Dummy() {
const navigate = useNavigate()
return <div> Hello World <button onClick={() => navigate('/someRoute')}> </div>
}
Then my code uses it in a different project that is just imported.
(in the #dummyInc/site project)
App.js
import React from 'react'
import Dummy from '#dummyInc/components'
export function App() {
return <div> <Dummy /> </div>
}
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './src/App'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
Now I have the above and when I try to render it in the browser, it says the following, but I'm not sure how that's possible, it's being rendered in that context.
Error: useNavigate() may be used only in the context of a <Router> component.
Am I missing something? Any help is appreciated.
I have a scenario with 2 components:
App
People
I want to test if People gets rendered 10 times inside App. So, I'm trying to test that using Jest. So far, I did this on my src/App.test.js:
import React, { Component } from "react";
import People from "./components/People";
import App from './App';
test('Total people = 10', () => {
expect(App).find(People).toHaveLength(10);
});
But I get a message saying:
TypeError: expect(...).find is not a function.
How can I test how many times a component gets rendered inside another component using React and Jest? Can anyone help me?
For testing react components first you need to render them, there are some tools for doing that, but since your reasoning in this test is to check how many times a component has been rendered inside another component, enzyme does a good job with its shallow method.
import React from "react";
import App from "./App";
import People from "./components/People";
import { shallow } from "enzyme";
it("Total people = 10", () => {
const wrapper = shallow(<App />);
expect(wrapper.find(People)).toHaveLength(10);
});
You'll need to set up enzyme in your project first, read the docs for more details.
The current trend in testing is to check for the things the user actually sees in the page, so most people is using react-testing-library, It'll be good for you to check it out
If you ever switch to react-testing-library, you might write the test something like this:
import React, { Component } from "react";
import App from './App';
import {render} from "#testing-library/react";
test('Total people = 10', async () => {
const { getAllByText } = await render(<App />);
expect(getAllByText('string_in_People')).toHaveLength(10);
});
Basically you'd use one of the library's built-in getAllBy... query methods to query for all instances of an element that appears exactly once in each instance of your <People /> component. The resulting set's length will equal the number of <People /> instances on the page.
I am trying to declare two different React elements that I would like to render. The both elements are separated elements such as displayed elements (App.jsx) and the customized account system (Login.jsx). But in my test I have the same code in the both jsx file to ensure that the issue is not related to a specific part of them.
I have also created an /imports/startup/client/index.js file (called in the /client/main.js file):
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import './accounts-config.js';
import App from '/imports/ui/App.jsx';
import Login from '/imports/ui/Login.jsx';
Meteor.startup(() => {
render(<App />, document.getElementById('app'));
render(<Login />, document.getElementById('login'));
})
and the /client/main.html contains the related div tags:
...
<div id="app"></div>
<div id="login"></div>
...
The issue is that the second render is never displayed (here, the div login) and I observe that only the first render is interpreted.
All the examples that I've found only deals with a single react element. So I wonder how to use several separated react elements like it is in my html file ?
I am newbie in the meteorjs and react world , so maybe I didn't get the right philosophy...
You can make use of React 16 new feature that is portal.
For how to use ReactDOM.createPortal please refer to following link:
How to use ReactDOM.createPortal() in React 16?
I have solved my issue using only one render in the Meteor.startup(() (in my index.js).
The React doc specifies that only one render can be declared in the Meteor.startup(() (in my index.js).
https://reactjs.org/docs/components-and-props.html
My code is the following:
in my index.js
Meteor.startup(() => {
render(<App />, document.getElementById('app'));
})
The trick is that this Super component (App.jsx) has to be used to call all the other components. In my example by calling the Login component:
render() {
return (
<div className="container">
<Login />
</div>
)
}
I believe because the render() statement has an implicit return statement as well, so since it can only execute and return one, the next render statement isn't executed.
I try to enable HMR on my project with typescript and webpack 2 but whenever I make a change I see the following output in the logs and the store is reset to its original values(discards state)
index.js:832 MobX Provider: Provided store 'appStore' has changed. Please avoid replacing stores as the change might not propagate to all children
The UI is refreshed partially after loading the hot update bundle which is good and expected but since the store lost its state, the UI is not the expected one.
What is the right pattern for keeping the state of mobx stores across HMR updates?
Currently the coode looks like the following:
const uiStore = new UiStore();
const appStore = new AppStore();
function render() {
ReactDOM.render(
<AppContainer>
<Provider appStore={appStore} uiStore={uiStore}><App/></Provider>
</AppContainer>, document.getElementById('root'))
}
const hot = (module as any).hot
if (hot)
hot.accept(() => {
render()
})
render()
The problem was that after every hot reload, my index file that was referencing App component was re-required by the webpack on the client side and this was destroying the uiStore and appStore objects that was initialised in the index file.
Declaring the store as a member of the window object has solved the problem. The stores now survive across hot module replacements.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {AppContainer} from 'react-hot-loader';
import {observable} from 'mobx';
import {Provider} from 'mobx-react';
import {AppStore, UiStore, Stores} from './types/index';
import App from './components/App';
import './index.css';
declare var stores:Stores;
(window as any).stores = (window as any).stores || new Stores(new UiStore(), new AppStore());
function render() {
ReactDOM.render(
<AppContainer>
<App {...stores} />
</AppContainer>, document.getElementById('root'));
}
const hot = (module as any).hot
if (hot)
hot.accept(() => {
render();
})
render();
Each time you reload new page from another, your top component might be re-rendered which cause call
const uiStore = new UiStore();
const appStore = new AppStore();
each times.
this might be complained by mobx because you are replacing whole stores with new instance, which is not intended by Mobx.
Might be better if you create uiStore, appStore as a state, which still remain renders new pages.
I am writing this question cause I would like to ask you for some help in how to use the redux on my functional components. I had a look at other examples with React components but I cannot understand how to get the "store" value in functional components.
My idea is to use my
store.getState()
To check states and interact with the UI, inside my functional component but I cannot make it happen.
Any help please ?
For example, a functional component :
import React from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Header.css';
import { Navbar, Nav } from 'react-bootstrap';
import HeaderMenu from '../HeaderMenu';
import cx from 'classnames';
function Header() {
return (
<Navbar fluid fixedTop id="Header" className={s.navContainer}>
<Nav block className={cx(s.HeaderTitle, s.hideOnSmall)}>Project title</Nav>
<HeaderMenu />
</Navbar>
);
}
export default withStyles(s)(Header);
How can I use the "store" object inside my Header component ? It works on my App component, just I don't know how to use it within my components.
My questions are:
Should I use actions for retrieving the state instead ??
Should I pass the store object component to the component properties?
Thanks in advance!
EDIT :
I am using https://github.com/kriasoft/react-starter-kit
with the redux branch https://github.com/kriasoft/react-starter-kit/tree/feature/redux
As of version 7.x react-redux now has hooks for functional components.
Header.jsx
import React from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Header.css';
import { Navbar, Nav } from 'react-bootstrap';
import HeaderMenu from '../HeaderMenu';
import cx from 'classnames';
import { useSelector } from 'react-redux'
function Header() {
const store = useSelector(store => store)
return (
<Navbar fluid fixedTop id="Header" className={s.navContainer}>
<Nav block className={cx(s.HeaderTitle, s.hideOnSmall)}>Project title</Nav>
<HeaderMenu />
</Navbar>
);
}
export default withStyles(s)(Header);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
As Dan Abramov mentioned in his insanely famous Egghead.io series, presentational component shouldn't be aware of Redux store and shouldn't use it directly. You should create something called container component, which will pass necessary state fields + action callbacks to your presentational component via properties.
I highly recommend to watch Dan Abramov's Egghead.io series if above concepts are not familiar to you. Patterns he is describing there are de facto standard style guide for writing React+Redux applications nowadays.
If you want to get the Redux state on a functional component, you either have to manually connect the component and Redux, which is very tedious. You would have to access the reducer variable inside your React Component, meaning import the reducer into the component file among other configurations.
This would interfere with other benefits you would normally get, such as action creators, dispatching actions automatically through middleware, and more.
A cleaner idea is to just use the Provider Component that comes with React-Redux to turn your Header component into a Container. A Container is a react component that 'listens for' any changes that have been made to the store. You are essentially wrapping your Header component in a higher order component that is connected directly to the redux store.
This way is more scalable and you can easily create a boilerplate file that can be used with any React/Redux project.
Try to understand the individual modules/components a boilerplate project contains before going with it. If you are new to react (and its complementary libraries) I recommend you start here:
https://github.com/petehunt/react-howto
For redux:
http://redux.js.org/
These are both great ressources which clarify the majority of react related questions on stackoverflow.
You can use react-redux library, and using connect you will access your store data as a component props - it's easy and efficient.