How can convert Class Component constructor to Functional Component?
FROM CLASS COMPONENT
constructor(props) {
super(props);
this.state = {
myText: 'I\'m ready to get swiped!',
gestureName: 'none',
backgroundColor: '#fff'
};
}
TO FUNCTIONAL COMPONENT
const Component = () => {
//CODE
}
To change your class to functions you must know what is hooks: so what is a hooks?: They let you use state and other React features without writing a class.
to define the state you will use useState function(useState it one kooks)
so your factional component will look like the following:
import React, {useState} from 'react';
const Component = () => {
const [myText, setMyText] = useState('I\'m ready to get swiped!');
const [gestureName, setGestureName] = useState('none');
const [backgroundColor, setBackgroundColor] = useState('#fff');
return ....
}
To learn more about functionals component and their hooks check their doc:
https://reactjs.org/docs/hooks-intro.html
Related
Sorry. I'm new to react native and react.
And I just encountered setCount is not a function. (In 'setCount(1)','setCount' is undefined) error.
How can I use setCount Method in AComponent?
import React, {useState} from 'react';
import {
Text,
} from 'react-native';
const AComponent = ({count, callback}) => {
callback(1);
return <Text>{count}</Text>;
};
const App = () => {
const [count, setCount] = useState(0);
return <AComponent count={count} callback={setCount} />;
};
const styles = StyleSheet.create({
container: {},
});
export default App;
You are renaming your function to callback.
So in your component you need to use callback instead of setCount, or rename your props callback to setCount (preferable):
return <AComponent count={count} setCount={setCount} />
Each key={value} defined when you use your component, can be accessed with the key in the component.
I suggest you to have a deep read of the following article: https://reactjs.org/docs/components-and-props.html
I'm trying to wrap my mind around using Context in my React Native app that uses React Navigation. I think I am way off on this one. I am simply trying to pass the name of a book to my entire app through the navigation stacks.
App.js
const BookContext = React.createContext();
class BookProvider extends Component {
state = {
name: 'book name'
}
render() {
return (
<BookContext.Provider value={{
name: this.state.name
}}>
{this.props.children}
</BookContext.Provider>
)
}
}
export default function App() {
return (
<BookProvider>
<BookContext.Consumer>
{({ name }) => (<Routes name={name} />)} //my react navigation stacks component
</BookContext.Consumer>
</BookProvider>
);
}
and in Book.js (a component in the navigation stack)
componentDidMount() {
console.log(this.context)
}
returns an empty object {}
Any help is appreciated!
To save you some Googling, this is the correct approach: https://github.com/react-navigation/react-navigation/issues/935#issuecomment-359675855
Another way, if you're using a relatively new version of React, and your component in question at that route is a functional component, is to use the useContext React hook.
e.g.
import React, { useContext } from 'react'
import { BookContext } from '/path/to/BookContext'
function BookConsumerComponent() {
const { name } = useContext(BookContext);
console.log(name);
}
I need to figure out how to test a component method that doesn't return a value and doesn't change any of the states of its component, all it does is push another screen.
I'm using jest and enzyme to access a class methods and states.
This is the method I want to test (if possible):
signUp() {
this.props.navigation.push('Signup');
}
Yep, just pass in a mock for the navigation prop:
import * as React from 'react';
import { shallow } from 'enzyme';
class SimpleComponent extends React.Component {
signUp() {
this.props.navigation.push('Signup');
}
render() { return null; }
}
test('signUp', () => {
const navigationMock = { push: jest.fn() };
const wrapper = shallow(<SimpleComponent navigation={navigationMock}/>);
wrapper.instance().signUp();
expect(navigationMock.push).toHaveBeenCalledWith('Signup'); // Success!
});
I'm testing a react-native Component which imports a Class LanguageStore. Currently the test fails because the component is instantiating this class which calls a private setter that is undefined in the scope of the test:
FAIL src\modules\languageProvider\__tests__\LanguageProvider-test.js
● renders correctly
TypeError: _this.strings.setLanguage is not a function
at LanguageStore.setLanguage (src\modules\languageProvider\LanguageStore.js:25:15)
at new LanguageProvider (src\modules\languageProvider\LanguageProvider.js:30:16)
Question:
How to hoist a jest dependency mock over actual dependency?
In order to resolve this I called a jest.mock according my to this answer How can I mock an ES6 module import using Jest?. But I get the same error as before because the test is calling the implementation of LanguageStore rather than the mock I created below - _this.strings.setLanguage is not a function:
import { View } from 'react-native';
import React from 'react';
import { shallow } from 'enzyme';
import renderer from 'react-test-renderer';
import connect from '../connect.js';
import LanguageProvider from '../LanguageProvider';
import LanguageStore from '../LanguageStore';
it('renders correctly', () => {
const TestComponent = connect(Test);
const strings = { test: 'Test' };
const language = "en"
const stringsMock = {
setLanguage: jest.fn()
};
const mockSetLanguage = jest.fn();
jest.mock('../LanguageStore', () => () => ({
language: language,
strings: stringsMock,
setLanguage: mockSetLanguage,
}));
const wrapper = shallow(<LanguageProvider strings={strings} language="en"><Test /></LanguageProvider>);
expect(wrapper.get(0)).toMatchSnapshot();
});
class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
return <View />;
}
}
This is a link to the test and related components and classes under test:
https://github.com/BrianJVarley/react-native-prototyping/blob/i18nProvider-feature/src/modules/languageProvider/tests/LanguageProvider-test.js
Calling jest.mock within a test doesn't work.
You'll need to move your mock outside of the test and make sure your factory function doesn't have any external dependencies.
Something like this:
import { View } from 'react-native';
import React from 'react';
import { shallow } from 'enzyme';
import connect from '../connect.js';
import LanguageProvider from '../LanguageProvider';
import LanguageStore from '../LanguageStore';
jest.mock('../LanguageStore', () => {
const language = "en"
const stringsMock = {
setLanguage: jest.fn()
};
const mockSetLanguage = jest.fn();
return () => ({
language,
strings: stringsMock,
setLanguage: mockSetLanguage,
})
});
it('renders correctly', () => {
const TestComponent = connect(Test);
const strings = { test: 'Test' };
const wrapper = shallow(<LanguageProvider strings={strings} language="en"><Test /></LanguageProvider>);
expect(wrapper.get(0)).toMatchSnapshot();
});
class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
return <View />;
}
}
Why isn't my component's state computed property updating after Redux store updates its value?
I am using some helper methods to grab the sub-store via AppStore.getState().ApiStore for my isAuthenticated state property. It seems like when this store value updates, the component state value does not update. Does React Native not watch for store updates in computed component state properties?
My component looks like the below:
// Vendor
import React, { Component } from 'react'
import { AppRegistry, Text, View, StyleSheet, TextInput, Button} from 'react-native'
import AppStore from './Stores/AppStore'
import StoreHelpers from './Stores/StoreHelpers'
// Custom
import Login from './Components/Login/Login'
import Api from './Services/Api.js'
// Styles
const styles = StyleSheet.create({
mainView: {
flex: 1,
padding: 20,
marginTop: 30,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#3b5998',
},
});
// Main App Component
export default class Main extends Component {
constructor(props) {
super(props)
this.state = {
isLoading: false,
isAuthenticated: !StoreHelpers.getApiStore().userBalanceResponse.error // Computed property from store
}
// Enable this for debugging
console.log(this.state)
AppStore.subscribe(() => {
console.log(AppStore.getState())
})
}
render() {
return (
<View style={styles.mainView}>
<Login />
</View>
)
}
}
// skip this line if using Create React Native App
// AppRegistry.registerComponent('AwesomeProject', () => Main);
You can't see it because your component is not subscribed to the store. Anything to do with store is the job of redux and NOT React Native. So if you wrap your component inside react-redux connect and pass in mapStateToProps to it you should get the right computed value.
// ... rest of imports
import { connect } from 'react-redux';
// Main App Component
class Main extends Component {
constructor(props) {
super(props)
this.state = {
isLoading: false,
isAuthenticated: this.props.isAuthenticated,
}
// ... rest of code
}
// ... rest of code
}
const mapStateToProps = (store) => ({
isAuthenticated: !userBalanceResponse: store.userBalanceResponse.error,
});
export default connect(mapStateToProps, null)(Main);
To make it work, make sure that you set up redux store properly. Wrap your root component within a Provider component and pass in store into it. Suppose your root component is called App, then it would look something like the following:
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import Main from 'path-to-main/Main';
// we will pass this store to the Provider
const store = createStore(
reducer,
// ... middlewares etc this is optional
);
export default class App extends Component {
render() {
return(
<Provider store={store}>
<Main />
</Provider>
)
}
}