I'm trying to use this library https://github.com/country-regions/react-country-region-selector for my react native application.
The example code is as follows:
import React from "react";
import { View, Text } from 'react-native';
// note that you can also export the source data via CountryRegionData. It's in a deliberately concise format to
// keep file size down
import {
CountryDropdown,
RegionDropdown,
CountryRegionData
} from "react-country-region-selector";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { country: "", region: "" };
}
selectCountry(val) {
this.setState({ country: val });
}
selectRegion(val) {
this.setState({ region: val });
}
render() {
const { country, region } = this.state;
return (
<View>
<CountryDropdown
value={country}
onChange={val => this.selectCountry(val)}
/>
<RegionDropdown
country={country}
value={region}
onChange={val => this.selectRegion(val)}
/>
</View>
);
}
}
export default Example;
I changed the divs in the render method into View, which has left me with the current error: Invariant Violation: View config not found for name option.
I'm not sure if this is because the library is intended for React as opposed to React-Native or if there is something else going on that I'm unaware of.
This won't work because this library renders HTML, which is not available in react-native. You can confirm this by going to node_modules/react-country-region-selector/src to see the source code.
However, the Picker component in react-native has a very similar API, so you could easily remake this to be compatible. Note that you should not edit files in your node_modules as they will be corrected any time you run yarn / npm. Instead, you should create your own local version of this module.
It's really just a matter of replacing select with Picker and option with Picker.Item and changing the onChange handlers to work with the Picker instead of expecting a DOM event.
You can learn more about the Picker API here
Related
I am trying to add a drop down calendar but I get warning from the code below and
there is not drop down calendar when cursor was placed over the input box.
Warning from the developer tool, console panel:
VM2542 react-dom.development.js:86 Warning: componentWillReceiveProps has been renamed, and >is not recommended for use. See https://reactjs.org/link/unsafe-component-lifecycles for details.
Move data fetching code or side effects to componentDidUpdate.
If you're updating state whenever props change, refactor your code to use memoization
techniques or move it to static getDerivedStateFromProps. Learn more at: >https://reactjs.org/link/derived-state
Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all >deprecated lifecycles to their new names, you can run npx react-codemod rename-unsafe->lifecycles in your project source folder.
Please update the following components: DateInput
ExpenseForm.js
import React from "react";
import moment from "moment";
import 'react-dates/lib/css/_datepicker.css'
import 'react-dates/initialize';
import { SingleDatePicker } from "react-dates";
export default class ExpenseForm extends React.Component {
state = {
createdAt: moment(),
calendarFocused: false
}
onDateChange = (createAt) => {
this.setState(()=>({createAt}))
}
onFocusChange = ({focused}) => {
this.setState(()=>{calendarFocused: focused})
}
render(){
return (
<div>
<SingleDatePicker
date={this.state.createdAt} // momentPropTypes.momentObj or null
onDateChange={this.onDateChange} // PropTypes.func.isRequired
focused={this.state.calendarFocused} // PropTypes.bool
onFocusChange={this.onFocusChange} // PropTypes.func.isRequired
numberOfMonths={1}
isOutsideRange={()=>false}
/>
<button>Submit</button>
</div>
)
}
}
I am also getting a hint warning on VSCode on the line:
import 'react-dates/initialize';
Could not find a declaration file for module 'react-dates/initialize'. 'c:/Users/PEI WAI LEE/Programming/ReactCourse/my-provider/node_modules/react-dates/initialize.js' implicitly has an 'any' type.
If the 'react-dates' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dates'ts(7016)
I change this line
onFocusChange = ({focused}) => {
this.setState(()=>{calendarFocused: focused})
}
to
onFocusChange = ({focused}) => {
this.setState(()=>({calendarFocused: focused}))
}
without the brackets the statement won't return calendarFocused
The calendar is now showing when I hover the cursor to the input box
can someone advise the warning and the hit warning on VSCode?
I am following a guide to upgrade to React 18. After completing the upgrade I am seeing errors on certain pages in my app.
ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported in React 18.
I am not using the unstable_renderSubtreeIntoContainer() function anywhere in my app, but when I look closer at what is causing these errors it seems to be caused my Bootstrap components.
Is there anyway to update this to remove the errors?
I ran into the same problem with react-bootstrap#v0.33.1 specifically when using OverlayTrigger component after upgrading to React 18. The warning message suggests to migrate to using portals. So I implemented a CustomOverlayTrigger component that leverages portals and referred to React's portal documentation to do so. Note that this solution is for Bootstrap 3 usage of OverlayTrigger (react-bootstrap v0.33.1). It seems later versions of react-bootstrap got rid of using ReactDOM.unstable_renderSubtreeIntoContainer. If you are not in a position to migrate to later versions (like I am), this solution will help for this use case. I have not check thoroughly if other components use the deprecated method, but the approach might be the same.
First of all, I copied the original source of the OverlayTrigger component code located here. You will need to clean up the imports and include into your code the utils function createChainedFunction located here.
I then created a portal wrapper based off React's documentation that looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
const tooltipRoot = document.getElementById('tooltip-root');
class PortalWrapper extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
tooltipRoot.appendChild(this.el);
}
componentWillUnmount() {
tooltipRoot.removeChild(this.el);
}
render() {
// eslint-disable-next-line react/destructuring-assignment
return ReactDOM.createPortal(this.props.children, this.el);
}
}
PortalWrapper.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
};
export default PortalWrapper;
At the top, you can see the line const tooltipRoot = document.getElementById('tooltip-root');, I simply added in my index.html a div next to the react app's root div that will server as the anchor for my portal.
Then, back in the CustomOverlayTrigger component copied from react-bootstrap, I edited it in the follwing manner:
Remove all references to this._overlay and this._mountNode because the PortalWrapper now manages the mounting/unmounting. So I deleted componentDidMount(), componentDidUpdate(), componentWillUnmount() and renderOverlay()
I modified makeOverlay so that its result is wrapped by PortalWrapper so it became the following:
makeOverlay(overlay, props) {
return (
<PortalWrapper>
<Overlay
{...props}
show={this.state.show}
onHide={this.handleHide}
target={this}
>
{overlay}
</Overlay>
</PortalWrapper>
);
}
Finally, I changed the render method's return statement to become:
return (<>
{cloneElement(child, triggerProps)}
{this.makeOverlay(overlay, props)}
</>);
After this, I simply had to replace all my invocations to OverlayTrigger with CustomOverlayTrigger and I had the same result without the warning message.
I trying to use multiselect-react-dropdown package inside my stencil project, but while rendering I'm getting this error, I found many solution for react but nothing really worked, Can anyone help do same in stenciljs.
import { Component, h, State } from '#stencil/core';
import { Multiselect } from 'multiselect-react-dropdown';
#Component({
tag: 'ui-card',
styleUrl: 'style.scss',
shadow: true
})
export class UiCard {
#State() state: any;
constructor() {
this.state = {
options: [{ name: 'Srigar', id: 1 }, { name: 'Sam', id: 2 }]
};
}
onSelect(selectedList, selectedItem) {
console.log(selectedItem)
console.log(selectedList)
}
onRemove(selectedList, removedItem) {
console.log(selectedList)
console.log(removedItem)
}
render() {
return (<div>
<Multiselect
options={this.state.options}
selectedValues={this.state.selectedValue}
onSelect={this.onSelect}
onRemove={this.onRemove}
/>
</div>)
}
}
StencilJS is not related to React.
Indeed they both are using JSX/TSX as a markup language, but React uses it's own React implementation of it, while StencilJS uses h jsxFactory.
As you may know, JSX is transpired to the regular function calls like createElement which return a Virtual DOM object to render.
So, to render react Virtual DOM object to the page you need to call ReactDOM.render(), meanwhile Stencil compiles it to the web-components.
Despite a lot of common things like JSX, props/state and other - React and StencilJS are completely different tools.
You can use <slot> as a workaround, but I think there might be some performance issues.
Though I wouldn't recommend it, it's possible to use react components inside Stencil, by including the react runtime in your component (yeah sounds pretty ineffective).
See my answer here: https://stackoverflow.com/a/62046928/2897426. It's for using a react-bootstrap component which is fairly similar. Note that Stencil's JSX (or really TSX) is not compatible with React's JSX, thus you can't use JSX to pass the properties. It'll be something like
import { Component, h, State } from '#stencil/core';
import { Multiselect } from 'multiselect-react-dropdown';
import ReactDOM from 'react-dom';
import React from 'react';
#Component({
tag: 'ui-card',
styleUrl: 'style.scss',
shadow: true
})
export class UiCard {
#Element() host: HTMLUiCardElement;
#State() state: any;
#Watch('state')
onStateChange() {
const props = {
options: this.state.options,
// ...
};
ReactDOM.render(React.createElement(Multiselect, props), this.host);
}
componentWillLoad() {
this.onStateChange();
}
render() {
return <Host />;
}
}
Again, I don't recommend doing this, it'll completely bloat your component with the whole react runtime. Just saying it's possible.
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!
I have included material-ui (and react-tap-event-plugin) in my project and added 3 buttons to one of my components:
<RaisedButton onClick={this.props.onSave} label="Save" style={styles.button}/>
<RaisedButton label='Publish' onClick={this.props.onPublish} style={styles.button}/>
<RaisedButton label='Cancel' onClick={this.onCancel.bind(this)} style={styles.buttonCancel}/>
when I click on any of these, they go very dark grey and when I click again, they go black (and stay like that). The whole applications goes bonkers, the react routing no longer works (I can see the URL changing in the address bar, but the view doesn't refresh). This all looks pretty bad for a button click :)
Any idea what I may be doing wrong? (I take care of the childContext as described in the docs, so the muiTheme is loaded).
I forgot to check the console... there are 3 exceptions whenever I press the button:
1)
vendor.js:12 Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded (details: https://facebook.github.io/react/warnings/refs-must-have-owner.html).(…)
2)
ReactTransitionGroup.js:176 Uncaught TypeError: Cannot read property 'componentWillLeave' of undefined(…)
3)
vendor.js:12 Uncaught Error: removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded (details: https://facebook.github.io/react/warnings/refs-must-have-owner.html).(…)
In the component that uses FlatButton (or RaisedButton neither work) I have this:
1) Import:
import FlatButton from 'material-ui/FlatButton'; //eslint-disable-line
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
2) in the class
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
3) and a static declaration:
EditorComponent.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
Feels like I'm doing all that's required.
This may be related to what I'm experiencing:
https://github.com/callemall/material-ui/issues/2818
So probably the issue is caused by material-ui distributing it's own version of React? What's the point in that? But... my version of material-ui doesn't have a node_modules folder, so no extra React either...
Source for a component importing and using FlatButton
import React from 'react'; // eslint-disable-line
import Input from '../../../components/common/textInput'; // eslint-disable-line
import BaseEditorComponent from '../base/EditorComponent';
import FlatButton from 'material-ui/FlatButton'; //eslint-disable-line
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
export default class EditorComponent extends BaseEditorComponent {
constructor() {
super();
this.state = {
textValue: 'Enter value'
};
}
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
_onChange(e) {
this.setState({
textValue: e.target.value
});
}
render() {
return (
<div>
<Input
value={this.state.textValue}
name="SimpleText"
label="Simple Text Value:"
onChange={this._onChange.bind(this)}
/>
<FlatButton label="Test"/>
</div>
);
}
}
EditorComponent.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
Also, the BaseEditorComponent:
import React from 'react';
import widgetActions from '../../widgets/WidgetActions';
import widgetInstanceStore from '../../widgets/WidgetInstanceStore';
export default class EditorComponent extends React.Component {
constructor() {
super();
}
componentDidMount() {
this.setState(widgetInstanceStore.getWidgetInstanceState(this.props.widgetId) || {});
}
save() {
widgetActions.saveWidgetInstanceState(this.props.widgetId, this.state);
}
}
Have you tried to use onTouchTap instead of onClick?
If #1 doesn't help, please show more code - component with above code and it's parent component.
As per https://github.com/callemall/material-ui/issues/2818 the solution was to include react-addons-transition-group alongside react in the browserify bundle. So it's good to know that it's not only NPM where a 2nd copy of react can slip through, but also browserify or webpack.
Thanks https://stackoverflow.com/users/3706986/piotr-sołtysiak for helping with the issue today!