I'm trying to use the new getDerivedStateFromProps lifecycle method in my React Native component but the method never gets called. I've tried looking it up but found no issues in the react-native repo. No results on StackOverflow or Google either.
What I did find are a reddit thread and a StackOverflow issue which both cite updating react-dom as a solution, which would not work in this case since there's no dom in React Native.
Can anyone confirm if this method is supposed to work in React Native? If it can be used, any help with solving this issue will be much appreciated.
Below is a simplified version of my component:
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Auth } from '../redux';
import ChillaAPI from '../api';
const withUserData = WrappedComponent => {
class UserDataLoader extends React.Component {
static getDerivedStateFromProps(props, state) {
console.log('getDerivedStateFromProps');
if (props.uid !== state.uid) {
return {
uid: props.uid,
};
}
return state;
}
state = { uid: null };
render() {
console.log({ propsUid: this.props.uid });
console.log({ stateUid: this.state.uid });
return <WrappedComponent />;
}
}
UserDataLoader.propTypes = {
uid: PropTypes.bool.isRequired,
};
return connect(mapStateToProps)(UserDataLoader);
};
function mapStateToProps(state) {
return {
uid: Auth.selectors.getUid(state),
};
}
export default withUserData;
The log output from the component is as follows:
{ propsUid: null }
{ stateUid: null }
{ propsUid: 'jW78ej3JDgPpheadAlcrkG8UIZB2' }
{ stateUid: null }
Here is my package.json for good measure:
{
"name": "Chilla",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"start:reset": "node node_modules/react-native/local-cli/cli.js start --reset-cache",
"watch:lint": "node node_modules/eslint-watch/bin/esw -w",
"test": "jest",
"precommit": "lint-staged"
},
"lint-staged": {
"*.js": [
"node_modules/.bin/prettier --single-quote --trailing-comma es5 --write",
"eslint",
"git add"
]
},
"dependencies": {
"axios": "^0.18.0",
"firebase": "^4.13.1",
"husky": "^0.14.3",
"lint-staged": "^7.0.4",
"prop-types": "^15.6.1",
"react": "16.3.1",
"react-native": "^0.52.2",
"react-native-fetch-blob": "^0.10.8",
"react-native-image-picker": "^0.26.7",
"react-navigation": "^1.5.11",
"react-redux": "^5.0.7",
"recompose": "^0.27.0",
"redux": "^4.0.0",
"redux-logger": "^3.0.6"
},
"devDependencies": {
"babel-eslint": "^8.2.3",
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"eslint-plugin-react-native": "^3.2.1",
"eslint-watch": "^3.1.4",
"jest": "22.4.3",
"prettier": "^1.12.1",
"react-test-renderer": "16.3.1"
},
"jest": {
"preset": "react-native"
}
}
Updating to react-native#0.55.3 solved this issue
Related
I'm working on a Next.js app right now using version 12.1.5, and I'm running into a really crazy bug. Every input component is causing a full re-render on every keystroke, leading to a loss of focus on the input. This applies to input, textarea, and even the #monaco-editor/react package. I had the same issue in Formik forms, and was weirdly able to solve the problem by switching to react-hook-form. But, I'm still seeing it on all of my components that accept keystrokes.
I've tried moving the component's value state up the tree, tried putting the state local to the component, and I've had absolutely no luck. This is what my input component looks like:
Input.tsx
import { forwardRef, InputHTMLAttributes, ReactNode, Ref } from 'react';
import * as LabelPrimitive from '#radix-ui/react-label';
import css from 'classnames';
import { Flex } from 'containers/flex/Flex';
import s from './Input.module.scss';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
showLabel?: boolean;
icon?: ReactNode;
}
export const Input = forwardRef(
(
{ showLabel, name, className, label, icon, ...rest }: InputProps,
ref: Ref<HTMLInputElement>
) => {
return (
<Flex column className={css(s.input, className)}>
{showLabel && (
<LabelPrimitive.Label htmlFor={name} className={s.input__label}>
{label}
</LabelPrimitive.Label>
)}
<Flex alignCenter className={s.input__icon}>
{icon && icon}
</Flex>
<input
ref={ref}
name={name}
{...rest}
className={css(s.input__field, icon && s.hasIcon)}
/>
</Flex>
);
}
);
Input.displayName = 'Input';
If I implement a value like this:
TestComponent.tsx
import { useState } from 'react';
import { Input } from 'elements/input/Input';
export const TestComponent = () => {
const [value, setValue] = useState('');
return <Input value={value} onChange={setValue}/>;
};
Any time I try to type I lose focus. Again, this has happened on every implementation of inputs that I've tried outside of react-hook-form, and includes the #monaco-editor/react package.
Here, also, is my package.json in case I've got any issues with other packages.
package.json
{
"name": "app",
"version": "0.6.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest",
"test:watch": "jest --watch",
"vercel:build": "prisma generate && prisma migrate deploy && next build",
"dev:connect": "pscale connect veroskills development --port 3309",
"shadow:connect": "pscale connect veroskills shadow --port 3309",
"slicemachine": "start-slicemachine",
"prepare": "husky install"
},
"dependencies": {
"#hookform/resolvers": "^2.8.8",
"#monaco-editor/react": "^4.4.4",
"#next-auth/prisma-adapter": "^1.0.3",
"#prisma/client": "^3.13.0",
"#prismicio/client": "^6.4.2",
"#prismicio/helpers": "^2.2.1",
"#prismicio/next": "^0.1.2",
"#prismicio/react": "^2.2.0",
"#prismicio/slice-simulator-react": "^0.2.1",
"#radix-ui/react-alert-dialog": "^0.1.7",
"#radix-ui/react-checkbox": "^0.1.5",
"#radix-ui/react-dialog": "^0.1.7",
"#radix-ui/react-dropdown-menu": "^0.1.6",
"#radix-ui/react-icons": "^1.1.0",
"#radix-ui/react-label": "^0.1.5",
"#radix-ui/react-progress": "^0.1.4",
"#radix-ui/react-scroll-area": "^0.1.4",
"#radix-ui/react-select": "^0.1.1",
"#radix-ui/react-separator": "^0.1.4",
"#radix-ui/react-switch": "^0.1.5",
"#radix-ui/react-tabs": "^0.1.5",
"#radix-ui/react-toast": "^0.1.1",
"#radix-ui/react-toolbar": "^0.1.5",
"#radix-ui/react-tooltip": "^0.1.7",
"bcryptjs": "^2.4.3",
"classnames": "^2.3.1",
"dayjs": "^1.11.0",
"next": "^12.1.5",
"next-auth": "^4.3.1",
"next-compose-plugins": "^2.2.1",
"next-images": "^1.8.4",
"next-react-svg": "^1.1.3",
"node-mocks-http": "^1.11.0",
"path": "^0.12.7",
"plyr-react": "^3.2.1",
"prismic-reactjs": "^1.3.4",
"react": "^18.0.0",
"react-code-blocks": "^0.0.9-0",
"react-dom": "^18.0.0",
"react-gravatar": "^2.6.3",
"react-hook-form": "^7.30.0",
"react-loading-skeleton": "^3.1.0",
"react-select": "^5.2.2",
"react-table": "^7.7.0",
"react-use-keypress": "^1.3.1",
"sass": "^1.50.0",
"swr": "^1.3.0",
"use-monaco": "^0.0.40",
"yup": "^0.32.11"
},
"devDependencies": {
"#prismicio/types": "^0.1.27",
"#types/bcryptjs": "^2.4.2",
"#types/jest": "^27.4.1",
"#types/node": "17.0.21",
"#types/react": "18.0.1",
"#types/react-dom": "^18.0.0",
"#types/react-gravatar": "^2.6.10",
"#types/react-table": "^7.7.10",
"#typescript-eslint/eslint-plugin": "^5.18.0",
"eslint": "8.12.0",
"eslint-config-next": "12.1.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.0",
"jest": "^27.5.1",
"lint-staged": "^12.3.7",
"prettier": "^2.6.2",
"prisma": "^3.13.0",
"slice-machine-ui": "^0.3.7",
"ts-jest": "^27.1.4",
"turbo": "^1.2.4",
"typescript": "^4.6.3"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"yarn eslint --fix",
"yarn prettier --write"
]
}
}
I am completely at a loss here; does anyone have idea what the issue could be?
I've figured out my problem through some extensive debugging. I have a reusable Flex component that utilizes createElement to allow me to create a flex box of any element by passing in an element type- div, button, nav etc, and I use that component within my input component. Getting rid of my createElement function and replacing it with a simple div fixed the problem, so now I just need to refactor the Flex component to still allow for any element type.
All that to say, the Flex component was causing a full render whenever it's children changed. Off to correct.
I am using jest to create snapshots of react-native components. I'm using babel 7. I can create snapshots but Snapshot is not created for TouchableOpacity component
I have already tried updating react-test-renderer to latest version but that does not help.
The snapshot test file --
Button.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import Button from '../src/components/Button';
test('renders correctly', () => {
const tree = renderer.create(<Button />).toJSON();
expect(tree).toMatchSnapshot();
});
Button.js
const Button = (props: Props) => {
const { text, disabled, style, onPress } = props
return (
<TouchableOpacity
style={[styles.button, style]}
disabled={disabled}
activeOpacity={disabled ? 1 : 0.5}
onPress={!disabled && onPress}
>
<Text style={styles.buttonText}>{text}</Text>
</TouchableOpacity>
)
}
here's the error message for jest
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6884
The above error occurred in the <AnimatedComponent> component:
in AnimatedComponent (created by TouchableOpacity)
in TouchableOpacity (created by Button)
in Button
TypeError: Cannot read property 'bind' of undefined
at new bind (node_modules/react-native/Libraries/Animated/src/createAnimatedComponent.js:39:53)
Here's my package.json
{
"name": "",
"version": "0.0.1",
"scripts": {
"test:unit": "jest",
"test": "jest",
},
"jest": {
"preset": "react-native",
"testMatch": [
"**/?(*.)test.js?(x)"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"setupFiles": [
"<rootDir>/jest/setup.js"
]
},
"dependencies": {
"#babel/runtime": "^7.1.2",
"react": "16.5.0",
"react-native": "0.57.2",
},
"devDependencies": {
"#babel/core": "^7.1.2",
"#babel/plugin-proposal-class-properties": "^7.1.0",
"#babel/preset-env": "^7.1.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^9.0.0",
"babel-jest": "^23.6.0",
"babel-preset-flow": "^7.0.0-beta.3",
"detox": "^9.0.4",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "1.6.0",
"enzyme-to-json": "^3.3.4",
"eslint": "^5.6.0",
"flow-bin": "0.78.0",
"husky": "^0.14.3",
"jest": "23.6.0",
"jest-snapshot": "^23.6.0",
"lint-staged": "^7.3.0",
"metro-react-native-babel-preset": "0.45.4",
"mocha": "^5.2.0",
"react-test-renderer": "16.5.2",
"regenerator-runtime": "^0.12.1"
}
}
Here's my bable.config.js
module.exports = api => {
api.cache(true);
return {
presets: [
'module:metro-react-native-babel-preset',
'flow',
'#babel/preset-env'
],
plugins: ['#babel/plugin-proposal-class-properties']
};
};
Here's my .babelrc
{
"presets": ["module:metro-react-native-babel-preset", "flow"]
}
Update your babel.config.js plugins list to include "#babel/plugin-transform-flow-strip-types" before the class-properties plugin:
plugins: [
"#babel/plugin-transform-flow-strip-types",
"#babel/plugin-proposal-class-properties"
]
Reference:
https://github.com/facebook/react-native/issues/20150#issuecomment-417858270
I want to use enzym-chai in cypress.
My source code looks like this
ProductList
import React from 'react'
import Product from './Product'
export default class ProductList extends React.Component {
render() { return (<div className = 'ui unstackable items'>
<Product />
</div>);
}
}
Product
import React from 'react'
export default class Product extends React.Component {
render () {
return (
<div className = 'item'>
<div className = 'image'>
<img src="../images/Banana-Snowboard.png" alt="Snow Board" ></img>
</div>
<div className = 'middel aligned content'>
<div className = 'description'>
<a>Snow Board</a>
<p>Cool Snow Board</p>
</div>
<div className = 'extra'>
<span>Submitted by:</span>
<img className = 'ui avatar image' src= './images/avatar.png' alt="Avatar"></img>
</div>
</div>
</div>
)
}
}
An the test looks like this
import React from 'react';
import ReactDOM from 'react-dom';
import Enzyme from 'enzyme';
import { configure, mount,shallow } from 'enzyme'
import chaiEnzyme from 'chai-enzyme'
import chai from 'chai'
import ProductList from '../../src/components/ProductList';
import Product from '../../src/components/Product'
import Adapter from 'enzyme-adapter-react-16'
Enzyme.configure({ adapter: new Adapter() });
chai.use(chaiEnzyme())
function myAwesomeDebug (wrapper) {
let html = wrapper.html()
// do something cool with the html
return html
}
chai.use(chaiEnzyme(myAwesomeDebug))
describe('ProductList component testing', () => {
it('Should display one product in a productlist' , ()=> {
const productList = mount(<ProductList />)
expect(productList).to.be.present()
expect(productList.find('div')).to.be.present()
expect(productList).to.have.descendants(Product)
});
});
The configuration file looks like this:
{
"name": "react-hello-world",
"version": "1.0.0",
"description": "React Hello World",
"main": "index.js",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"cypress": "cypress open",
"cypress:all": "cypress run --browser chrome"
},
"author": "CodeMix",
"license": "ISC",
"dependencies": {
"react-scripts": "^1.1.1"
},
"devDependencies": {
"#cypress/webpack-preprocessor": "^2.0.1",
"ajv": "^6.5.2",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"chai": "^4.1.2",
"chai-enzyme": "^1.0.0-beta.1",
"cheerio": "^1.0.0-rc.2",
"css-loader": "^0.28.7",
"cypress": "^3.0.2",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^4.18.0",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-chai-friendly": "^0.4.1",
"eslint-plugin-cypress": "^2.0.1",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-react": "^7.10.0",
"eslint-plugin-standard": "^3.1.0",
"hoek": "^5.0.3",
"lodash": "^4.17.10",
"react": "^16.4.1",
"react-dom": "^16.4.1"
},
"peerDependencies": {
"chai": "^3.0.0 || ^4.0.0",
"cheerio": "0.19.x || 0.20.x || 0.22.x || ^1.0.0-0",
"enzyme": "^2.7.0 || ^3.0.0",
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0",
"react-dom": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0"
}
}
I get following error message when I executing the test TypeError: expect(...).to.be.present is not a function I get a similar error message when I try some of the other assertions describe >in https://github.com/producthunt/chai-enzyme#installation How do I fix the configuration so I can use the chai-enzyme assertions?
Its looks like you forgot to import expect!
import { expect } from 'chai'
I am trying to compile my react website. But whenever I try to build, it fails. I keep getting
Module not found: Can't resolve 'autosuggest-highlight/match'
I have react-drawer just outside where this file is, as well as my npm and node modules up to date. Every time I try to update the files, or make a change, it doesn't even start to compile and crashes at "react-script start".
This is the code for the page that crashed:
import React from 'react';
import Autosuggest from 'react-autosuggest';
import * as AutosuggestHighlightMatch from 'autosuggest-highlight/match';
import * as AutosuggestHighlightParse from 'autosuggest-highlight/parse';
import ApiRequest from './ApiRequest.js';
class Search extends React.Component {
componentDidMount() {
new ApiRequest('GET', '/clientlist').send((res, people) => {
if (res.status == 200) {
this.setState({people});
} else if (res.status == 401 || res.status == 403) {
console.log('authentication error');
}
});
}
constructor() {
super();
this.state = {
value: '',
suggestions: [],
people: [],
selection: ''
};
this.renderSuggestion = (suggestion, {query}) => {
const suggestionText = `${suggestion.name}`;
const matches = AutosuggestHighlightMatch(suggestionText,query);
const parts = AutosuggestHighlightParse(suggestionText, matches);
return (
<span className='suggestion-content '
style={{backgroundImage: `url(${suggestion.profileimg || 'http://s3.amazonaws.com/37assets/svn/765-default-avatar.png'})`}}>
<span className="name">
{
parts.map((part, index) => {
const className = part.highlight ? 'highlight' : null;
return (
<span className={className} key={index}>{part.text}</span>
);
})
}
</span>
</span>
)
};
This is the image of my folder hierarchy:
Here is my Package.Json
{
"name": "medimo",
"version": "0.1.0",
"private": true,
"dependencies": {
"autosuggest-highlight": "^3.1.0",
"chart.js": "^2.6.0",
"es6-object-assign": "^1.1.0",
"history": "^1.17.0",
"moment": "^2.18.1",
"parse-react": "^0.5.2",
"parse-server": "^2.5.3",
"parse5": "^3.0.2",
"postcss": "^6.0.9",
"postcss-cssnext": "^3.0.2",
"react": "^15.6.1",
"react-autosuggest": "^9.3.2",
"react-chartjs-2": "^2.5.7",
"react-dom": "^15.6.1",
"react-dropdown": "^1.2.5",
"react-image": "^1.0.1",
"react-motion-drawer": "file:../custom-deps/react-motion-drawer",
"react-router": "^4.1.2",
"react-router-dom": "^4.1.2",
"react-scripts": "1.0.10",
"react-sortable-hoc": "^0.6.7",
"react-tabs": "^1.1.0",
"socket.io-client": "^2.0.3",
"socket.io-react": "^1.2.0",
"utils": "^0.3.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:3001",
"devDependencies": {
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-preset-react": "^6.24.1",
"html-webpack-plugin": "^2.30.1",
"postcss-loader": "^2.0.6",
"webpack": "^3.4.1",
"webpack-dev-server": "^2.6.1"
}
}
I had the same problem with the exact same package funnily enough.
This is what I have that fixed it:
import AutosuggestHighlightMatch from "autosuggest-highlight/umd/match";
import AutosuggestHighlightParse from "autosuggest-highlight/umd/parse";
The dependency needs to be added it seems like:
npm i autosuggest-highlight
What solved the problem for me was to:
Delete node_modules directory
run npm install
Check-in official page document, following the way of import also working
import AutosuggestHighlightMatch from "autosuggest-highlight/match";
import AutosuggestHighlightParse from "autosuggest-highlight/parse";
I am getting the following error when I am trying to build my React Native bundle.
Syntax Error components/Example/index.js: Unexpected token, expected ; (1:20)
I am not sure if it's a problem with my eslint/babel configs. Here are the files.
components/Example/index.js
export default from './View'
components/Example/View.js
import React, { Component, PropTypes, Button } from 'react';
import { connect } from 'react-redux'
import { updateExampleData } from '../../actions/example'
class Example extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
navigator: PropTypes.object.isRequired,
exampleProp: PropTypes.object.isRequired
}
const incrementData = () => {
const newIncrement = this.props.exampleProp + 1
updateExampleData(newIncrement)
}
render() {
return (
<View>
<Text>exampleData: {this.props.exampleProp} </Text>
<Button
onPress={incrementData}
title="Increment Data"
color="#841584"
/>
</View>
)
}
}
const mapStateToProps = (state, props) => {
const exampleProp = state.example.example
const newProps = {
exampleProp: exampleProp
}
return newProps
}
export default connect(mapStateToProps)(Example)
package.json
{
"name": "SportsApp",
"version": "0.1.0",
"private": true,
"devDependencies": {
"babel-eslint": "^7.2.3",
"babel-preset-react-native": "^3.0.2",
"eslint": "^4.5.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.1.1",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^7.3.0",
"eslint-plugin-standard": "^3.0.1",
"jest-expo": "~19.0.0",
"react-native-orientation": "^3.0.0",
"react-native-orientation-listener": "0.0.4",
"react-native-scripts": "1.1.0",
"react-native-tableview-simple": "^0.16.8",
"react-redux": "^5.0.5",
"react-test-renderer": "16.0.0-alpha.12",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-promise": "^0.5.3",
"redux-thunk": "^2.2.0"
},
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"scripts": {
"start": "react-native-scripts start",
"eject": "react-native-scripts eject",
"android": "react-native-scripts android",
"ios": "react-native-scripts ios",
"test": "node node_modules/jest/bin/jest.js --watch"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"expo": "^19.0.0",
"react": "16.0.0-alpha.12",
"react-native": "^0.46.1"
}
}
eslint.json
{
"parser": "babel-eslint",
"env": {
"browser": true
},
"plugins": [
"react"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"rules": {
}
}
.babelrc
{
"presets": ["react-native"]
}
I have written react-redux before but I did not do the parsing configurations for that project so I am wondering if the syntax error has something to do with that. I am pretty sure my index.js files for the components were written with the same syntax as that in the provided file where the syntax error is.
Can you try the following?
export { default } from './View'
In your index.js