React native + mobx dont re render - reactjs

Iam currently building an application with react native and mobx. My problem is that the component is not re-rendered after a observable value from the store is changed. My code looks as following:
components/phoneNumberChange.js:
#inject('store')
#observer export class PhoneNumberChange extends React.Component{
renderPhoneInput = () => (
<React.Fragment>
<Button onPress={() => this.props.store.showCountryPicker()}>
<Text>Show picker</Text>
</Button>
</React.Fragment>
);
render = () => (
<React.Fragment>
<CountryCodePicker visible= {this.props.store.pickerVisible}/>
</React.Fragment>
);
}
screens/loginScreen.js:
import { Provider } from "mobx-react";
import { store } from "stores/phoneNumberChangeStore.js";
import { PhoneNumberChange } from "components/phoneNumberChange.js";
export class LoginScreen extends React.Component{
render = () => (
<Provider store={store}>
<PhoneNumberChange/>
</Provider
);
}
stores/phoneNumberChangeStore.js:
import { observable, action } from "mobx";
class PhoneNumberChangeStore {
#observable pickerVisible;
constructor(){
this.hideCountryPicker();
}
#action hideCountryPicker = () => {
this.pickerVisible = false;
}
#action showCountryPicker = () => {
this.pickerVisible = true;
}
}
export const store = new PhoneNumberChangeStore();
babel.config.js:
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
[
"#babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]
};
};
package.json:
{
"name": "myapp",
"main": "app/app.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"eject": "expo eject"
},
"dependencies": {
"#babel/plugin-proposal-decorators": "^7.3.0",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-preset-react-native": "^4.0.1",
"expo": "^32.0.0",
"mobx": "^5.9.0",
"mobx-react": "^5.4.3",
"prop-types": "^15.7.2",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-native-animatable": "^1.3.1",
"react-native-ui-kitten": "^3.1.2",
"react-navigation": "^3.3.2"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0"
},
"private": true
}
The countryCodePicker gets shown or not when the visible prop changes. This is working. but when i change a value from the store it doesnt update and gets shown. I would appreciate any help!
Cheers

You are exporting your store singleton as default in phoneNumberChangeStore.js, but you are importing a named export PhoneNumberChangeStore in loginScreen.js.
Use the default export in loginScreen.js instead. The store property is also called pickerVisible, not countryCodePickerVisible.

Found the solution! I redefined render on the instance.
I changed render = () => {..} to render(){ return (...); }
cheers!

Related

TypeError: null is not an object (evaluating 'dispatcher.useMemo')

I'm trying to use InversifyJS with MobX in my React Native application but I got this error:
ERROR TypeError: null is not an object (evaluating 'dispatcher.useMemo')
I don't use useMemo anywhere. My application is almost empty, I've just installed these packages:
{
"name": "abc",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"#eva-design/eva": "^2.1.1",
"#react-native-async-storage/async-storage": "~1.17.3",
"#ui-kitten/components": "^5.1.2",
"#ui-kitten/eva-icons": "^5.1.2",
"core-js": "^3.26.0",
"expo": "~46.0.16",
"expo-auth-session": "~3.7.1",
"expo-crypto": "~11.0.0",
"expo-random": "~12.3.0",
"expo-status-bar": "~1.4.0",
"expo-web-browser": "~11.0.0",
"mobx": "^6.6.2",
"mobx-react-lite": "^3.4.0",
"prettier": "^2.7.1",
"react": "18.0.0",
"react-dom": "18.0.0",
"react-native": "0.69.6",
"react-native-svg": "^12.4.4",
"react-native-web": "~0.18.7"
},
"devDependencies": {
"#babel/core": "^7.12.9",
"#types/react": "~18.0.14",
"#types/react-native": "~0.69.1",
"inversify": "5.0.1",
"inversify-inject-decorators": "3.1.0",
"typescript": "~4.3.5"
},
"private": true
}
my App.tsx:
import "core-js/proposals/reflect-metadata"
import React from "react"
import * as eva from "#eva-design/eva"
import { ApplicationProvider, IconRegistry, Button, Layout, Text, Icon } from "#ui-kitten/components"
import { EvaIconsPack } from "#ui-kitten/eva-icons"
import { StatusBar } from "expo-status-bar"
import { Provider, useInjection } from "./ioc/ioc.react"
import { container } from "./ioc/ioc"
export default () => (
<>
<IconRegistry icons={EvaIconsPack} />
<ApplicationProvider {...eva} theme={eva.light}>
<Provider container={container}>
<App />
</Provider>
</ApplicationProvider>
</>
)
const App = () => {
return (
<Layout style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Button accessoryLeft={<Icon name="google" />}>Sign In</Button>
<StatusBar style="auto" />
</Layout>
)
}
This error appears when i want to wrap my app component in Inversify IoC container.
That's how container looks like:
import React, { ReactNode, useContext } from "react"
import { Container, interfaces } from "inversify"
const InversifyContext = React.createContext<{ container: Container | null }>({ container: null })
type Props = {
container: Container
children: ReactNode
}
export const Provider: React.FC<Props> = (props) => {
return <InversifyContext.Provider value={{ container: props.container }}>{props.children}</InversifyContext.Provider>
}
export function useInjection<T>(identifier: interfaces.ServiceIdentifier<T>) {
const { container } = useContext(InversifyContext)
if (!container) {
throw new Error()
}
return container.get<T>(identifier)
}
Seems to be an issue with the new Expo SDK 47

react-router-native giving error in Expo CLI - React Native

I have installed react-router-native in my project using npm and I am getting an error saying:
E:/myapp/node_modules/react-router-native/NativeRouter.js,
11:9 Module parse failed: Unexpected token (11:9).... You may need an
appropriate loader to handle this file type, currently no loaders are
configured to process this file. See
https://webpack.js.org/concepts#loaders
package.json :
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"#material-ui/core": "^4.11.2",
"expo": "~40.0.0",
"expo-status-bar": "~1.0.3",
"firebase": "^8.2.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "~0.13.12",
"react-router-native": "^5.2.0"
},
"devDependencies": {
"#babel/core": "~7.9.0"
},
"private": true
}
The file where react-router-native is giving an error (NativeRouter.js):
import React from "react";
import { Alert } from "react-native";
import { MemoryRouter } from "react-router";
import PropTypes from "prop-types";
/**
* The public API for a <Router> designed for React Native. Gets
* user confirmations via Alert by default.
*/
function NativeRouter(props) {
return <MemoryRouter {...props} />;
}
NativeRouter.defaultProps = {
getUserConfirmation: (message, callback) => {
Alert.alert("Confirm", message, [
{ text: "Cancel", onPress: () => callback(false) },
{ text: "OK", onPress: () => callback(true) }
]);
}
};
const __DEV__ = true; // TODO
if (__DEV__) {
NativeRouter.propTypes = {
initialEntries: PropTypes.array,
initialIndex: PropTypes.number,
getUserConfirmation: PropTypes.func,
keyLength: PropTypes.number,
children: PropTypes.node
};
}
export default NativeRouter;

How to test React Native component with NavigationEvents in jest

How can I write a jest unit test for a react native component which contains a NavigationEvents subcomponent.
I've tried the solutions offered in questions here and here without success.
The error I am getting is
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9215
The above error occurred in the <Context.Consumer> component:
in withNavigation(NavigationEvents) (created by MyComponent)
in View (created by View)
in View (created by MyComponent)
in MyComponent
Consider adding an error boundary to your tree to customize error handling behavior.
● MyComponent test › renders
Invariant Violation: withNavigation can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.
Below is a minimal example that causes the error.
import 'react-native';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
import React from 'react';
import renderer from 'react-test-renderer';
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<NavigationEvents/>
</View>
);}
}
describe('MyComponent test', () => {
it('renders', () => {
jest.mock('react-navigation', () =>({
NavigationEvents: 'mockNavigationEvents',
withNavigation: component => component
}));
const navigation = { navigate: jest.fn() };
renderer.create(<MyComponent navigation={navigation}/>);
});
});
Edit
As requested in comments added package.json below:
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"eject": "expo eject",
"test": "node ./node_modules/jest/bin/jest.js --watchAll"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"#expo/samples": "2.1.1",
"#expo/vector-icons": "^10.0.0",
"expo": "^35.0.0",
"expo-camera": "~7.0.0",
"expo-sqlite": "^7.0.0",
"moment": "^2.24.0",
"react": "16.8.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
"react-native-action-button": "^2.8.5",
"react-native-calendar-picker": "^6.0.0",
"react-native-dialog": "^5.6.0",
"react-native-dotenv": "^0.2.0",
"react-native-dynamic-search-bar": "^0.1.11",
"react-native-elements": "^1.1.0",
"react-native-gesture-handler": "~1.3.0",
"react-native-keyboard-aware-scroll-view": "^0.9.1",
"react-native-modal-datetime-picker": "^7.4.0",
"react-native-paper": "^2.15.2",
"react-native-progress-circle": "^2.1.0",
"react-native-search-bar": "^3.4.2",
"react-native-vector-icons": "^6.4.2",
"react-navigation": "^3.0.9",
"expo-constants": "~7.0.0",
"expo-file-system": "~7.0.0"
},
"devDependencies": {
"babel-preset-expo": "^7.0.0",
"jest-expo": "^35.0.0"
},
"private": true
}
expo-cli version
$ expo-cli -V
3.13.1
The problem is that jest.mock has to be outside of describe and it functions. You don't need to manually mock navigation object since you're mocking the withNavigation HOC function:
// Setup mocks outside describe and it functions
jest.mock('react-navigation', () =>({
NavigationEvents: 'mockNavigationEvents',
withNavigation: component => component
}));
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<NavigationEvents/>
</View>
);
}
}
describe('MyComponent test', () => {
it('renders', () => {
renderer.create(<MyComponent/>);
});
});
And the renders test passes:
I suggest you have all those mocks inside a file and set setupFilesAfterEnv in package.json:
package.json > jest:
"jest": {
"preset": "jest-expo"
"setupFilesAfterEnv": ["./path/to/jestInit.js"]
},
jestInit.js:
jest.mock('react-navigation', () =>({
NavigationEvents: 'mockNavigationEvents',
withNavigation: component => component
}));
This way, you'll have those mocks for every Jest test file without having to include the mocks inside each test file.

Redux Usage Issue #connect [duplicate]

I'm new to using React and Redux, I'm building a simple todos application. I am writing my application using the create-react-app tool in the command line.
The issue
I went to other blogs and post and others have mentioned that I am missing an npm plugin to transform decorators "transform-decorators-legacy", I added this to my dependencies along with Babel, but I am still receiving the same error.
Syntax error: Unexpected token (9:0)
7 | import './App.css';
8 |
> 9 | #connect((store) => {
| ^
10 | return {
11 | user: store.user.user
12 | }
My code
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Todos from './components/Todos';
import Todo from './components/Todo';
import './App.css';
#connect((store) => {
return {
user: store.user.user
}
})
class App extends Component {
constructor(){
super()
this.state = {
name: 'Brad',
todos: [
{
id: '001',
name: 'Take out trash',
completed: false
},
{
id: '002',
name: 'Meeting with boss',
completed: false
},
{
id: '003',
name: 'Go out to dinner',
completed: false
}
]
}
}
render() {
return (
<div className="App">
<h1>Hello</h1>
<Todos name={this.state.name} todos={this.state.todos}/>
<Todo/>
</div>
);
}
}
export default App;
My dependencies
package.json
{
"name": "react-redux-project",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.16.2",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-promise-middleware": "^4.3.0",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel": "^6.23.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"react-scripts": "1.0.11"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Any help/knowledge will be appreciated thanks!
First I'd note that I agree with #markerikson's answer, use the function instead of the decorator.
If you did want to use decorators though, there would be a couple more steps involved. You've added the plugin to your dependencies, but not told Babel to use it.
Create React App uses Webpack with Babel under the hood, namely, in react-scripts. You need to adjust that Babel configuration. The "Create React App" way to do this is to eject from Create React App and then edit .babelrc - see https://babeljs.io/docs/plugins/transform-decorators/#usage-via-babelrc-recommended-
Please note that both the React and Redux teams generally discourage the use of decorators. Instead, in this case you should use connect() as a function:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
Try like this:
const stateMap = (state) => {
console.log('state', state);
return {
//something from state
};
};
export default connect(stateMap)(App);

Font.loadAsync() can't resolve module for custom fonts (React Native & Expo)

My app uses CRNA and Expo, and my issue is that the Font.loadAsync() asynchronous function can't locate a .otf font file in the assets/fonts/ folder in my project directory. I am absolutely sure that the directory and file names are correct. I receive this error.
link to image of my error screen
Here is my code:
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Font, AppLoading } from 'expo'
import Root from './js/Root';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
fontLoaded: false
}
}
async componentDidMount() {
await Font.loadAsync({
"Light": require('./assets/fonts/SemplicitaPro-Light.otf')
})
this.setState({ fontLoaded: true })
}
render() {
if (!this.state.fontLoaded) {
return <AppLoading />
}
return <Root />;
}
}
Here is my package.json:
{
"name": "Zumer",
"version": "0.1.0",
"private": true,
"devDependencies": {
"flow-bin": "^0.40.0",
"jest-expo": "^0.4.0",
"react-native-scripts": "0.0.28",
"react-test-renderer": "16.0.0-alpha.6"
},
"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",
"flow": "flow"
},
"packagerOpts": {
"assetExts": ["ttf", "otf"]
},
"jest": {
"preset": "jest-expo",
"tranformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-navigation)"
]
},
"dependencies": {
"#expo/vector-icons": "^4.0.0",
"expo": "^16.0.0",
"native-base": "^2.1.2",
"react": "16.0.0-alpha.6",
"react-native": "^0.43.4",
"react-native-elements": "^0.11.1",
"react-navigation": "^1.0.0-beta.8",
"react-redux": "^5.0.4",
"redux": "^3.6.0",
"redux-observable": "^0.14.1",
"redux-persist": "^4.6.0",
"rxjs": "^5.3.0"
}
}
Could it be that the .otf file format isn't supported by Expo?
I fixed this issue by converting the otf files to ttf
I had a similar issue and I was able to resolve it by removing the quotes around the key that requires the font source.
Before:
await Font.loadAsync({
"Light": require('./assets/fonts/SemplicitaPro-Light.otf')
})
After
await Font.loadAsync({
Light: require('./assets/fonts/SemplicitaPro-Light.otf')
})
And using it in the stylesheet like so
const styles = StyleSheet.create({
text: {
fontFamily: 'Light'
}
});
Everything worked fine after that.

Resources