Trying to install the GetStreamChat React JS API but getting:
Invalid hook call. Hooks can only be called inside of the body of a function component.
I followed the debug guide from https://reactjs.org/warnings/invalid-hook-call-warning.htmlbut still unable to figure it out.
The guide lists 3 commons causes but I went through all of them.
Common Cause 1: Mismatching Versions of React and React DOM?
I am using react-dom#16.13.1
Common cause 2: Breaking the Rules of Hooks?
This is how I'm implementing the functional component:
chatbox.js -> this is straight copied and pasted from their API tutorial guide. It works in an app all by itself.
import React from 'react';
import { Chat, Channel, ChannelHeader, Window } from 'stream-chat-react';
import { MessageList, MessageInput, MessageLivestream } from 'stream-chat-react';
import { MessageInputSmall, Thread } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';
import 'stream-chat-react/dist/css/index.css';
const chatClient = new StreamChat('XYZ');
const userToken = 'XYZ';
chatClient.setUser(
{
id: 'crimson-rice-9',
name: 'Crimson rice',
image: 'https://getstream.io/random_png/?id=crimson-rice-9&name=Crimson+rice'
},
userToken,
);
const channel = chatClient.channel('livestream', 'spacex', {
image: 'image here',
name: 'Bruh Goes Boi',
});
const ChatBox = () => (
<Chat client={chatClient} theme={'livestream dark'}>
<Channel channel={channel} Message={MessageLivestream}>
<Window hideOnThread>
<ChannelHeader live />
<MessageList />
<MessageInput Input={MessageInputSmall} focus />
</Window>
<Thread fullWidth />
</Channel>
</Chat>
);
export default ChatBox;
testscreen2.js
import ChatBox from "../Chat/ChatBox"
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
const TestPage2 = () => {
return (
<div>
<p>Why you not work</p>
<ChatBox/>
</div>
)
}
export default TestPage2
Common Cause 3: Duplicate React
Running npm ls react produces:
starter-template#1.0.0 /Users/michaelninh/WebstormProjects/Shuriken
└─┬ stream-chat-react#2.2.0
└─┬ react-file-utils#0.3.15
└─┬ react-file-icon#0.2.0
└── react#16.13.1
Since I don't have multiple reacts showing, does this mean I only have one react copy? However when I do the other suggested test, it produces false which the guide says that I have two React copies:
// Add this in node_modules/react-dom/index.js
window.React1 = require('react');
// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
PRODUCES FALSE
If I do have multiple react copies, I am unsure how to debug since I'm a beginner at this.
Silly me. I installed the package in my project packages folder instead of the the client packages.
Related
I'm trying the new state management library from facebook recoil, I tried the Getting started example on a reactjs project and it worked perfectly. After that I tried recoil on a react-native project but I got an error:
Here's the code I've tried:
App.js
import React from 'react';
import {RecoilRoot} from 'recoil';
import RecoilTest from './RecoilTest';
const App = () => {
return (
<RecoilRoot>
<RecoilTest />
</RecoilRoot>
);
};
export default App;
RecoilTest.js
import React from 'react';
import {useRecoilState} from 'recoil';
import {View, Text} from 'react-native';
import {textState} from './Atoms';
const RecoilTest = () => {
const [text, setText] = useRecoilState(textState);
return (
<View>
<Text>{text}</Text>
</View>
);
};
export default RecoilTest;
Atoms.js
import {atom} from 'recoil';
export const textState = atom({
key: 'textState',
default: 'initial value',
});
Recoil don't has a fully support to react native yet
Towards release
See here
Hi everyone! FYI we've published a "nightly build" branch for testing purposes. If you want to try out recoil with react native before we release next version, try install the nightly branch with the "install git branch" feature of npm/yarn:
npm install https://github.com/facebookexperimental/Recoil.git#nightly
Or
yarn add https://github.com/facebookexperimental/Recoil.git#nightly
It is supported in nightly build. If you want to try before it is released with next version, you can install it doing:
yarn add https://github.com/facebookexperimental/Recoil.git#nightly
The update can be followed in this PR
Update:
RN support is now there in Recoil.js as Experimental.
https://github.com/facebookexperimental/Recoil/releases/tag/0.1.1
Try using 'useRecoilValue' instead in your RecoilTest.js file
const [text, setText] = useRecoilValue(textState);
Here are my scripts that make a navigator for lingui-js.
I faced this error on my local:
×
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:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See ...react-invalid-hook-call for tips about how to debug and fix this problem.
"react": "^16.8.6",
"react-dom": "^16.8.6",
My file:
import * as React from "react";
import { useLingui } from "#lingui/react";
const Navigation = ({ i18n, locales }) => (
<select selected={i18n.locale}>
{Object.keys(locales).map(locale => (
<option key={locale} onClick={() => i18n.activate(locale)} value={locale}>
{locales[locale]}
</option>
))}
</select>
);
export default useLingui(Navigation);
Hooks must be used inside of components because of how they are executed by react. They need to store state against a component. You can read more about info how hooks work in this article from Dan Abramov from the React Team.
You can either use the hook inside of another component:
const App = props => {
const { i18n } = useLingui()
return <Navigation i18n={i18n} {...props} />
}
Or you can make your own HOC (Higher Order Component) that you can use like in the code you posted:
const withI18n = WrappedComponent => props => {
const { i18n } = useLingui()
return <WrappedComponent i18n={i18n} {...props} />
}
The HOC is used like this:
import * as React from "react";
import { withI18n } from "../withI18n";
const Navigation = ({ i18n, locales }) => (...);
export default withI18n(Navigation);
Sometimes it's also because you do this line:
npm install react-i18next i18next --save
under your root directory rather than your client/
(considering your structure:
root--client
root--api
hence, you have 2 react.
Just remove react-i18next & i18next under your package.json #root/ & remove your node_modules & package-lock.json files.
Do npm install react-i18next i18next --save under client/ instead.
I have imported useStats into my index page but when I use it it breaks gatsby/react and I get this 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 fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
I tried to trouble shoot using this from the site:
// Add this in node_modules/react-dom/index.js
window.React1 = require('react');
// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
But I got back true.
Here is my code:
import React, { useState } from "react";
import { Link } from "gatsby";
// components
import Layout from "../components/Layout/Layout";
import SEO from "../components/seo";
import IndexComponent from "../components/IndexComponent/IndexComponent";
const IndexPage = () => {
const [sku] = useState();
return (
<Layout>
<SEO title="Home" />
<IndexComponent />
</Layout>
);
};
export default IndexPage;
1.) you need [sku, setSku] = useState().
2.) Where are you rendering IndexPage? Are you doing IndexPage() instead of <IndexPage />?
I think It is a terminal Issue with windows.
Seams to work fine with bash.
I created complete offline ReactJS web application and I want to run it from android application from Web View using React-Native.
I followed the following procedure to do so:
1. I created a compiled ReactJS web application got the build using the following command:
npm run build
Then I created react-native project and placed the build folder with following architecture
I updated App.js with the following content:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, WebView} from 'react-native';
import {roscon} from "./build/index.html";
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={{height: 300, width: 300,overflow:'hidden' }}>
<WebView
source={{uri: roscon}}
scalesPageToFit={true}
domStorageEnabled={true}
javaScriptEnabled={true}
startInLoadingState={true}
/>
</View>
);
}
}
After running this code I expected it to run my ReactJS Web application, instead I got white screen.
Can you please tell what can be the causing issues and how i can make my ReactJS Web App run on react-native?
Note: I was able to run generated build folder using npm command
serve -s build
But I still can't figure out how to port it to react-native project as WebView
After research and testing, I found a solution.
The main issue i found was the compiled build folder is rendered as static html. And it needed a server to serve pages.
So, I followed this link for getting build project to get it up and running
Then, integrating it with nodejs Android Project Samples to get my build folder running in android as a Webview.
Note: I also tried react-snapshot and react-snap but they didn't gave satisfactory results.
Try to require the html file correctly and pass it in to source prop in this way:
<WebView
source={require('./build/index.html')}
/>
Install
npm install react-native-react-bridge
These are used to render React app in WebView
npm install react-dom react-native-webview
Requirements
react 16.8+
react-native 0.60+
Usage
Fix metro.config.js to use babelTransformer from this library.
module.exports = {
transformer: {
babelTransformerPath:
require.resolve('react-native-react- >.
.bridge/lib/plugin'),
...
},
};
Make entry file for React app. web.js
import React, { useState } from "react";
import {
webViewRender,
emit,
useSubscribe,
} from "react-native-react-bridge/lib/web";
const Root = () => {
const [data, setData] = useState("");
// useSubscribe hook receives message from React Native
useSubscribe((message) => {
if (message.type === "success") {
setData(message.data);
}
});
return (
<div>
<div>{data}</div>
<button
onClick={() => {
// emit sends message to React Native
// type: event name
// data: some data which will be serialized by JSON.stringify
emit({ type: "hello", data: 123 });
}}
/>
</div>
);
};
// This statement is detected by babelTransformer as an entry point
// All dependencies are resolved, compressed and stringified into one file
export default webViewRender(<Root />);
Use the entry file in your React Native app with WebView.
import React from "react";
import WebView from "react-native-webview";
import { useBridge } from "react-native-react-bridge";
import webApp from "./WebApp";
const App = () => {
// useBridge hook create props for WebView and handle communication
// 1st argument is the source code of React app
// 2nd argument is callback to receive message from React
const { ref, source, onMessage, emit } = useBridge(webApp, (message) => {
// emit sends message to React
// type: event name
// data: some data which will be serialized by JSON.stringify
if (message.type === "hello" && message.data === 123) {
emit({ type: "success", data: "succeeded!" });
}
});
return (
<WebView
// ref, source and onMessage must be passed to react-native-webview
ref={ref}
source={source}
onMessage={onMessage}
/>
);
};
I'm using react with redux and testing with cypress,
I was able to access the store using
cy.window().its('store').invoke('getState').then((state) => {}
But how do i access a component's local state rather than the application store?
I tried
cy.get('.simple-component').its('getState')
or
cy.get('.simple-component').invoke('getState')
but Cypress is returning "CypressError: Timed out retrying: cy.invoke() errored because the property: 'getState' does not exist on your subject"
And on the Cypress console (in chrome) it's yeilding:
Yielded:
<div class="simple-component" getstate="[object Object]"></div>
It seems that's caused by React removing the methods from the DOM so i need to access it in React rather than in the DOM?
import React, { Component } from 'react';
class simpleComponent extends Component {
constructor(props) {
super(props)
this.state = {
sample: "hello"
}
}
// getState() just for testing on cypress
getState() {
return this.state
}
render(){
return <div className="simple-component" getState={this.getState()}></div>
}
}
As an alternative can i export the local component state at the end of the simple-component using window.store?
>= version 7.0.0
As of Cypress 7.0, the new Component Test Runner is now bundled with Cypress
From https://www.cypress.io/blog/2021/04/06/cypress-component-testing-react:
We still need to install the react adapter to mount components:
yarn add -D cypress #cypress/react #cypress/webpack-dev-server
add a glob pattern matching your component tests to cypress.json:
{
"component": {
"testFiles": "**/*.test.{js,ts,jsx,tsx}",
"componentFolder": "src"
}
}
Tell Cypress to use #cypress/webpack-dev-server for component tests. in cypress/plugins/index.js:
const injectDevServer = require("#cypress/react/plugins/react-scripts")
module.exports = (on, config) => {
injectDevServer(on, config)
return config
}
This will configure the Cypress Webpack Dev Server to use the same Webpack configuration as Create React App uses.
If you are using a different template, like Next.js, we have some other adapters available. It's also possible to create your own adapter.
< version 7.0.0
There's a Cypress Plugin for that, called react-unit-test. It gives you the ability to mount React components directly (adds a cy.mount() command) and provides access to the component's internal state.
Here's an example from the repo's readme:
// load Cypress TypeScript definitions for IntelliSense
/// <reference types="cypress" />
// import the component you want to test
import { HelloState } from '../../src/hello-x.jsx'
import React from 'react'
describe('HelloState component', () => {
it('works', () => {
// mount the component under test
cy.mount(<HelloState />)
// start testing!
cy.contains('Hello Spider-man!')
// mounted component can be selected via its name, function, or JSX
// e.g. '#HelloState', HelloState, or <HelloState />
cy.get(HelloState)
.invoke('setState', { name: 'React' })
cy.get(HelloState)
.its('state')
.should('deep.equal', { name: 'React' })
// check if GUI has rerendered
cy.contains('Hello React!')
})
})
You can identify the element without mounting the react component. If you are testing your react app in isolation with the source code or writing functional UI test cases, you can consider a Cypress plugin called cypress-react-selector. It helps you identify web elements by component, props, and state even after the minification. You need to use React Dev Tool to identify the component names in that case.
Here is an example:
Suppose your react app:
const MyComponent = ({ someBooleanProp }) => (
<div>My Component {someBooleanProp ? 'show this' : ''} </div>
)
const App = () => (
<div id='root'>
<MyComponent />
<MyComponent name={bob} />
</div>
)
ReactDOM.render(<App />, document.getElementById('root'))
Then you can simply identify the react element like:
cy.getReact('MyComponent', { name: 'bob' } ).getCurrentState();
Find more sample test here
Hope it will help!