React Native - How to change data in js file using text input - react-native

My android app is loading string data from a js file that is looking like this:
module.exports = {
DATA: {
firstdata: 'data',
seconddata: 'data2'},
};
What I want to do, is change content of this file using text input with
onChangeText={(text) => data.DATA.firstdata.setState({text})}
But it tells me that "undefined is not a function".
These are my first attempts with text inputs. Any help will be appreciated :)

it seems you are trying to implement different concepts. You are trying to change js file using setState function, which is a function provided by react to change data in local component state. So, in your case, data.DATA.firstdata should be just a string, that doesn't know what setState function is. But, according to an error, it seems you are not even importing this DATA variable.
What you can do is set this data to your local state when component is mounted, and then mutate this local state with setState function.
...
import { DATA } from './path/to/the/file'
class MyComponent extends Component {
constructor(props) {
super(props)
this.state = {
firstdata: DATA.firstdata,
seconddata: DATA.seconddata,
};
}
render() {
return (
...
<TextInput onChangeText={(text) => this.setState({firstdata: text})}>
)
}
}

Related

Localization of React Native navigators

I am building an app where the users are prompted to choose their language the first time they launch the app. The language is then stored locally using AsyncStorage.
Every time the app launches the language is retrieved from storage and saved into the global.lang variable to be used by all components:
AsyncStorage.getItem('settings', (err, item) => {
global.lang = item.lang;
});
When I use the global.lang variable in the render() method in any component everything seems to be ok. However I run into trouble when trying to use the same variable when initializing my navigators:
const TabNavigator = createBottomTabNavigator(
{
Home: {
screen: HomeScreenNavigator,
navigationOptions:{
title: strings['en'].linkHome, --> this works
}
},
News: {
screen: NewsScreen,
navigationOptions:{
title: strings[global.lang].linkNews, --> this fails
}
}
});
I believe that this because the value is not retrieved from AsyncStorage by the time that the navigators are constructed. If I set the global.lang manually (eg. global.lang = 'en';) it seems to be OK, but not when I try to retrieve it from the storage.
Is there something that I am missing? Could I initialize the navigator with a default language and change the title later based on the value retrived?
Any help would be greatly appreciated.
The navigators are constructed in the app launch. So you would need to use some placeholder text and use the method described here where you change all screen titles based on the screen key...
Or... this sounds insane and i have never tried it. But you can use a loading screen where you retrieve the languaje settings. then... via conditional rendering you "render" a navigator component . Idk if it would work the same way , but you can try it. below some code that i just created for this purpose
export default class MainComponent extends React.Component {
constructor(props) {
super(props);
this.state = { hasLanguage:false};}
componentDidMount(){
this.retrieveLanguage()
}
async retrieveLanguage(){
//await AsyncStorage bla bla bla
//then
this.setState({hasLanguage:true})
}
render() {
return (
{
this.state.hasLanguage?
<View>
//this is a view that is rendered as a loading screen
</View>:
<Navigator/>//this will be rendered, and hence, created, when there is a language retrieved
}
);
}
}
Again. I don't know if react navigation creates the navigator at render . If so. When it creates a navigator , there should be the languaje to be used there

React Native - What's the different about this.state.data with this.data?

I was confused what's the different about this.state.data with this.data
let say I have a code like this:
componentWillMount(){
console.log(this.props.navigation.state.params.list);
api.get('my API Url')
.then((response)=> {
this.setState({data: JSON.parse(response.data)[0]})
this.data=JSON.parse(response.data)[0]
})
.catch((err)=>{
console.log("axios catching error")
Alert.alert("failed", "Retry to retrieve from API", [{text:'OK', onPress:()=>{this.componentWillMount()}}])
console.log(err)
})
}
constructor(props){
super(props);
this.state ={ data:[] }
this.data=[]
}
class Visit extends React.Component {
render() {
if (this.data.length==0){
return(
<Loader/>
)
}
return (
<Text>Visit</Text>
);
}
}
export default Visit;
with above code, I can't render <Text>Visit</Text> when this.data already have an array, but with this.state.data my App can rendering <Text>Visit</Text>,
so I want to know the different about this.state.data with this.data,
anyone can explain me?
this.state.data refers to data property of the current class state, while this.data refers to data property of current class.
A component's State is a trivial part of React environment, and if you can't understand this difference I suggest you to check this.
I also suggest you to check react official docs, almost everything from React applies to React Native, for me, React Native is almost the same as React, the only difference is you have more limited components in RN. We could say that RN is a subset of React
Note: property or properties it's not the same than component's props defined in React specs
For the purpose of React, it would be best to make use of the state. this.state.data refers to the data prop stored in the current component state. You can set the value by calling the setState method. On the other end, this.data refers to the data prop of the current class. You could change its value like you would other class variables in Javascript.

What is the <{}> syntax after extends Component?

I started a new project today using React Native 0.51.0 and noticed that the class syntax for the default project file had something new added, the <{}> syntax after extends Component:
export default class App extends Component<{}> {
...
}
I tried doing research but most search engines ignore special characters even with exact string matching, so trying to find out what this syntax is has proved to be difficult. I did some testing and was able to figure out that this change appeared in v0.49.0. The release notes make no mention of what this added syntax does though.
A lot of vague keyword searching and reading leads me to believe that this may be syntax related to TypeScript, but being unfamiliar with the language, I'm at a loss as to how to search and find out more about the syntax without knowing what the proper term for it is. Could anyone tell me what the name of the syntax and what it does? Specifically with regards to React Native.
It is related to Flow typings for the props you will receive in the component. Component<{}> would mean that you don't expect the component to receive props.
With Flow and React.Component, you can define types for props and state (see React$Component type declaration for details).
Example from Flow documentation about React components
import * as React from 'react';
type Props = { /* ... */ };
type State = {
count: number,
};
class MyComponent extends React.Component<Props, State> {
state = {
count: 0,
};
componentDidMount() {
setInterval(() => {
this.setState(prevState => ({
count: prevState.count + 1,
}));
}, 1000);
}
render() {
return <div>Count: {this.state.count}</div>;
}
}
<MyComponent />;

How to use global variables in React Native?

In React Native I want to use global variables when I am moving between different screens
Can anyone help me how to achieve it?
The global scope in React Native is variable global. Such as global.foo = foo, then you can use global.foo anywhere.
But do not abuse it! In my opinion, global scope may used to store the global config or something like that. Share variables between different views, as your description, you can choose many other solutions(use redux,flux or store them in a higher component), global scope is not a good choice.
A good practice to define global variable is to use a js file. For example global.js
global.foo = foo;
global.bar = bar;
Then, to make sure it is executed when project initialized. For example, import the file in index.js:
import './global.js'
// other code
Now, you can use the global variable anywhere, and don't need to import global.js in each file.
Try not to modify them!
Try to use global.foo = bar in index.android.js or index.ios.js, then you can call in other file js.
You can use the global keyword to solve this.
Assume that you want to declare a variable called isFromManageUserAccount as a global variable you can use the following code.
global.isFromManageUserAccount=false;
After declaring like this you can use this variable anywhere in the application.
You can consider leveraging React's Context feature.
class NavigationContainer extends React.Component {
constructor(props) {
super(props);
this.goTo = this.goTo.bind(this);
}
goTo(location) {
...
}
getChildContext() {
// returns the context to pass to children
return {
goTo: this.goTo
}
}
...
}
// defines the context available to children
NavigationContainer.childContextTypes = {
goTo: PropTypes.func
}
class SomeViewContainer extends React.Component {
render() {
// grab the context provided by ancestors
const {goTo} = this.context;
return <button onClick={evt => goTo('somewhere')}>
Hello
</button>
}
}
// Define the context we want from ancestors
SomeViewContainer.contextTypes = {
goTo: PropTypes.func
}
With context, you can pass data through the component tree without having to pass the props down manually at every level. There is a big warning on this being an experimental feature and may break in the future, but I would imagine this feature to be around given the majority of the popular frameworks like Redux use context extensively.
The main advantage of using context v.s. a global variable is context is "scoped" to a subtree (this means you can define different scopes for different subtrees).
Do note that you should not pass your model data via context, as changes in context will not trigger React's component render cycle. However, I do find it useful in some use case, especially when implementing your own custom framework or workflow.
Set up a flux container
simple example
import alt from './../../alt.js';
class PostActions {
constructor(){
this.generateActions('setMessages');
}
setMessages(indexArray){
this.actions.setMessages(indexArray);
}
}
export default alt.createActions(PostActions);
store looks like this
class PostStore{
constructor(){
this.messages = [];
this.bindActions(MessageActions);
}
setMessages(messages){
this.messages = messages;
}
}
export default alt.createStore(PostStore);
Then every component that listens to the store can share this variable
In your constructor is where you should grab it
constructor(props){
super(props);
//here is your data you get from the store, do what you want with it
var messageStore = MessageStore.getState();
}
componentDidMount() {
MessageStore.listen(this.onMessageChange.bind(this));
}
componentWillUnmount() {
MessageStore.unlisten(this.onMessageChange.bind(this));
}
onMessageChange(state){
//if the data ever changes each component listining will be notified and can do the proper processing.
}
This way, you can share you data across the app without every component having to communicate with each other.
If you just want to pass some data from one screen to the next, you can pass them with the navigation.navigate method like this:
<Button onPress={()=> {this.props.navigation.navigate('NextScreen',{foo:bar)} />
and in 'NextScreen' you can access them with the navigation.getParam() method:
let foo=this.props.navigation.getParam(foo);
But it can get really "messy" if you have more than a couple of variables to pass..
The way you should be doing it in React Native (as I understand it), is by saving your 'global' variable in your index.js, for example. From there you can then pass it down using props.
Example:
class MainComponent extends Component {
componentDidMount() {
//Define some variable in your component
this.variable = "What's up, I'm a variable";
}
...
render () {
<Navigator
renderScene={(() => {
return(
<SceneComponent
//Pass the variable you want to be global through here
myPassedVariable={this.variable}/>
);
})}/>
}
}
class SceneComponent extends Component {
render() {
return(
<Text>{this.props.myPassedVariable}</Text>
);
}
}

Importing Text from local json file in React native

I am wondering how the common way is to import a huge text to a View. In my case i am developing a React Native App for Android and iOS, and on one of my Views i want to present the "Terms of Use" document. Now when i just import/copy paste it into a Text Component it just can´t be the right solution, especially when i need to use localization to present the needed language. How would i "import" this Text-Block so it is nice formatted and i don´t need to put everything into my View:
<View style={styles.container}>
<Text style={styles.text}> |JSON - Text-file, with about 600 words -> Terms of Use document |</Text>
</View>
You can use:
import file from './config/TermsAndCondition.json';
then you can treat it as a javascript object:
file.description
I'd to it as JSON, especially if you need to bring some other (meta)data with the text. Where fetch(url) is called on componentWillMount and <Text>{this.state.hugeText}</Text> component is populated:
As a concept:
constructor(props) {
super(props);
this.state = {
hugeText: ''
};
}
componentWillMount() {
fetch('myText.json')
.then((res) => res.json())
.then((data) => {
this.setState({
hugeText: data.something
});
});
}
I tried fetch but it didn't work (wasn't able to find the file).
I tried this instead, and it worked:
// at top of file
var jsonData = require('./myfile.json');
// inside component definition
render() {
let deepProp = jsonData.whatever;
}