I have a button and when I toggle the button It changes the color.
This is the code:
state={
status:[
{toggle:false}
]
}
_onPress(){
const newState = !this.state.toggle
this.setState({toggle:newState})
}
render(){
const {toggle} = this.state
const textValue = toggle?"ON":"OFF"
const buttonBG = toggle?"#6AAAC6":"white"
const textColor = toggle?"white":"gray"
return(
<TouchableOpacity
onPress={()=>this._onPress()}
<Text>button</Text>
</TouchableOpacity>
)
}
}
But what if I have multiple buttons and they basically do the same function. Is there a way I could reuse this code without copy and pasting multiple times?
you can create a component call CustomButton
class CustomButton extends React.Component {
static defaultProps = {
onToggle: () => {},
}
state = {
status: [{ toggle: false }]
}
_onPress() {
const newState = !this.state.toggle
this.setState({ toggle: newState })
this.props.onToggle(newState)
}
render() {
const { toggle } = this.state
const textValue = toggle ? 'ON' : 'OFF'
const buttonBG = toggle ? '#6AAAC6' : 'white'
const textColor = toggle ? 'white' : 'gray'
return (
<TouchableOpacity onPress={() => this._onPress()}>
<Text>button</Text>
</TouchableOpacity>
)
}
}
and use anywhere you want
class App extends React.Component {
onButtonToggle = (isToggle) => {
console.log(isToggle)
}
render() {
return (
<View>
<CustomButton onToggle={this.onButtonToggle} />
</View>
)
}
}
Related
I have a stacknavigator and in headerTitle have a header component for each screen, heres the code:
const Home_stack = createStackNavigator({ //hooks
Home: {
screen: Home,
navigationOptions: ({navigation}) => {
return {
headerTitle: () => <Header navigation = {navigation} title = "Shum Note"/>}
}
},
Create: {
screen: Create,
navigationOptions: ({navigation}) => {
return {
headerTitle: () => <Childs_header navigation = {navigation} title = "Create Note"/>}
}
},
Edit: {
screen: Edit,
navigationOptions: ({navigation}) => {
return {
headerTitle: () => <Childs_header navigation = {navigation} title = "Edit Note"/>}
}
},
});
and this is the component Childs_header:
import Create_note from "../components/Create_note";
class Header extends Component {
comun = new Create_note();
render() {
return (
<>
<View style ={{backgroundColor: "white", flexDirection: "row", alignItems: "center"}}>
<View>
<Text style = {{color: "black", fontSize: 30, marginLeft: -20}}>{this.props.title}
</Text>
</View>
<View>
<Text>
<Feather name="check-square" size={24} color="black" onPress = {() => this.comun.save_data(this.props.navigation)}/>
</Text>
</View>
</View>
</>
);
}
}
export default Header;
as you can see I import the component Create_note and create an object of it to use one of its function, in this case save_data, but for some reason it isnt working, dont know if it has something to do with AsyncStorage becase with console.log("hi") it works, but saving data it doesnt, heres the structure of create_note component:
class Create_note extends Component {
state = {
content: "",
default_color: "#87cefa", //default color (cyan)
}
save_data = async() => {
if (this.state.content === "") {
//navigation.navigate("Home");
}else {
let clear_content = this.state.content.replace(/ /g,""); //replace al
try {
const data = await AsyncStorage.getItem("data");
if (data === null) {
const data = {"array_notes": [], "last_note": 0};
const last_note = data.last_note + 1;
const new_note = {note_number: last_note, content: clear_content, color: this.state.default_color, text_color: this.state.color}; //create a new_note object, note_number will be the key for each note
const array_notes = [];
array_notes.push(new_note);
data.array_notes = array_notes;
data.last_note = last_note;
await AsyncStorage.setItem("data", JSON.stringify(data)); //using stringify to save the array
//navigation.navigate("Home");
}else {
const data = JSON.parse(await AsyncStorage.getItem("data")); //use parse to acces to the data of the array
const last_note = data.last_note + 1;
const new_note = {note_number: last_note, content: clear_content, color: this.state.default_color, text_color: this.state.color};
const array_notes = data.array_notes;
array_notes.push(new_note);
data.array_notes = array_notes;
data.last_note = last_note;
await AsyncStorage.setItem("data", JSON.stringify(data));
//navigation.navigate("Home");
}
}catch(error) {
alert(error);
}
}
}
render() {
const props = {
screen: "create_note",
change_color: this.change_color.bind(this),
update_color: this.update_color.bind(this),
}
return (
<>
<ScrollView>
<RichEditor
ref = {this.richText}
onChange = {text => this.setState({content: text}, () => console.log(this.state.content))}
allowFileAccess = {true}>
</RichEditor>
</ScrollView>
{this.state.change_color ?
<Color
{...props}>
</Color>
: null}
<RichToolbar
editor = {this.richText}
onPressAddImage = {this.insertImage}
actions = {[
actions.insertBulletsList,
actions.insertOrderedList,
actions.insertImage,
"change_text_color",
]}
iconMap ={{
[actions.insertBulletsList]: () => <Text style = {this.styles.icon}><MaterialIcons name = "format-list-bulleted" size = {this.option_icon.size} color = {this.option_icon.color}/></Text>,
[actions.insertOrderedList]: () => <Text style = {this.styles.icon}><MaterialIcons name = "format-list-numbered" size = {this.option_icon.size} color = {this.option_icon.color}/></Text>,
[actions.insertImage]: () => <Text style = {this.styles.icon}><MaterialIcons name = "image" size = {this.option_icon.size} color = {this.option_icon.color}/></Text>,
change_text_color: () => <Text style = {this.styles.icon}><MaterialIcons name = "format-color-text" size = {this.option_icon.size} color = {this.option_icon.color}/></Text>,
}}
change_text_color = {this.change_color}
style = {{backgroundColor: "white"}}>
</RichToolbar>
<Button title = "save" onPress = {this.save_data}></Button>
</>
);
}
heres an image so you can see better the structure:
the function should run when I click in the check icon, in the blue button works because its part of the create_note component, but I want it in the check icon
From looking at your code I think the problem is that you're passing the navigation state object as a parameter to your save_data function in the onClick of your checkmark.
this.comun.save_data(this.props.navigation)
but the function definition of save_data doesn't take any parameters:
save_data = async () => {
// ...
};
So you could change the save_data function to something like this
save_data = async (navigation) => {
// ...
};
in order to have it work from inside the Header component.
If you want the save button, rendered by the Create_note component, to also call save_data onPress; you will have to pass the navigation state there as well.
I'm new to react native and want to make one function change state for the clicked button only not others that have the same function
as I explained in the title here is an example code
please any help & I know it might be a selly question but any answer will help
thanks a lot
export default class App extends Component {
constructor(){
super();
this.state = {
opened: true,
}
}
componentHideAndShow = () =>{
this.setState(previousState => ({opened: !previousState.opened}))
}
render() {
return (
{
this.state.opened ? <Text> hello</Text> : <Text> hello sdfsdfsdf</Text>
}
<Text onPress={this.componentHideAndShow}>test</Text>
{
this.state.opened ? <Text> hello</Text> : <Text> hello sdfsdfsdf</Text>
}
<Text onPress={this.componentHideAndShow}>test</Text>
);
}
}
This should work.
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
opened: [true, true]
};
}
componentHideAndShow = index => {
const opened = this.state.opened;
opened[index] = !opened[index];
this.setState({ opened: opened });
};
render() {
return (
<View>
{this.state.opened[0] ? (
<Text> hello</Text>
) : (
<Text> hello sdfsdfsdf</Text>
)}
<Button onPress={() => this.componentHideAndShow(0)}>test</Button>
{this.state.opened[1] ? (
<Text> hello</Text>
) : (
<Text> hello sdfsdfsdf</Text>
)}
<Button onPress={() => this.componentHideAndShow(1)}>test</Button>
</View>
);
}
}
Edit: you can do like this if you don't know the number of items:
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
const myArrayOfStrings = ['hello1', 'hello2', 'hello3', 'hello4', 'hello5'];
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
opened: undefined
};
}
componentDidMount() {
let opened = [];
myArrayOfStrings.map(item => {
opened.push(true);
});
this.setState({ opened: opened });
}
componentHideAndShow = index => {
const opened = this.state.opened;
opened[index] = !opened[index];
this.setState({ opened: opened });
};
render() {
const output = myArrayOfStrings.map((item, index) => {
return (
<View>
<Text>
{this.state.opened[index]
? `${item} is opened`
: `${item} is opened`}
</Text>
<Button onPress={() => this.componentHideAndShow(0)}>test</Button>
</View>
);
});
return <View>{output}</View>;
}
}
I am trying to select buttons and then display how many I selected. Something like this:
I selected 4 buttons and I want the text to show "selected:4". Also if I unselect 2, I want the text to show "selected:2.
This is my code:
class RegionBT extends Component {
static defaultProps = {
onToggle: () => {},
}
state = {
status: [{ toggle: false }],
count: ''
}
handleIncrement = () => {
this.setState({
count: this.state.count + 1
});
}
handleDecrement = () => {
this.setState({
count: this.state.count - 1
});
}
_onPress() {
const newState = !this.state.toggle
this.setState({ toggle: newState })
this.props.onToggle(newState)
{this.handleDecrement}
}
render() {
const { count } = this.state
const { toggle } = this.state
const buttonBG = toggle ? '#6AAAC6' : 'white'
const textColor = toggle ? 'gray' : 'gray'
return (
<TouchableOpacity
onPress={()=>this._onPress()}
style={{width:'70%', height:'70%',backgroundColor:buttonBG, justifyContent:'center',
borderColor:'#E0E0E0', borderWidth:1}}>
<Text style={{color:textColor, textAlign:'center', fontSize:13}}>{this.props.text}</Text>
<Text>{count}</Text>
</TouchableOpacity>
)
}
}
I think I did the code correctly but its not working. Any ideas?
I'm trying to display/store a list of items in my flatlist, but the problem is when I save an item and load that item in a different screen it is in a kind of repetition(look for the screen shot). And when I try to add different item, this new item will replace the previous item with the same kind of repetition. What I'm targeting is to have a list.
List_ScreenShot
Here is my code
AddModal.js
export default class AddModal extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible: props.modalVisible,
id: null,
count: 0,
price: null
};
}
state = {
text: '',
}
save = () => {
const { text } = this.state;
let myArray = {
text, text
}
AsyncStorage.setItem('myArray', JSON.stringify(myArray));
alert(text + 'saved');
}
onChange = (text) => {
this.setState({ text });
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
price: nextProps.price
})
}
render() {
console.log('inside AppModal', this.state.modalVisible);
return (
<View>
<TextInput style = { styles.input }
keyboardType = "numeric"
onChangeText = { this.onChange }
value = { this.state.text } //Item **
>
</TextInput>
</View>
<View}>
<TouchableOpacity
onPress = {() => { this.props.setModalVisible(false) }}
>
<Text style = { styles.buttonText }>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = { this.save }>
<Text style = { styles.buttonText }>Send</Text>
</TouchableOpacity>
</View>
)
}
}
Settlment.js
import Details from '../Menus/Details';
const key = '#MyApp:key';
export default class Settlement extends React.Component {
state = {
text: '',
storedValue: '',
myArray: ''
}
componentWillMount() {
//this.onLoad();
AsyncStorage.getItem('myArray')
.then(text => this.setState({ text }));
}
showData = async() => {
let myArray = await AsyncStorage.getItem('myArray');
let d = JSON.parse(myArray);
this.setState({ myArray : myArray });
}
render() {
const { myArray, text } = this.state;
return (
<View>
<TouchableOpacity onPress = {this.showData}>
<Text>Load Data</Text>
</TouchableOpacity>
<FlatList data = { this.state.myArray }
renderItem = {({ item }) =>
<Text>{myArray}</Text>
}
keyExtractor={(item, index) => index.toString()}
>
</FlatList>
</View>
);
}
}
What I see here:
const { text } = this.state;
let myArray = {
text, text
}
AsyncStorage.setItem('myArray', JSON.stringify(myArray));
alert(text + 'saved');
is an object called myArray, and nothing is being added to it. It's being defined and then assigned a value.
Maybe you could declare your array elsewhere like in the constructor (as an array, not an object, using myArray = []) and then use myArray.push(text) or if you want an array containing objects you can push object using myArray.push({ yourKeyName: text }). Also, it seems like the object you're storing in AsyncStorage is being replaced and not added to. But I'm not sure why you're getting multiple list items instead of just one.
PS - Where you're declaring state looks a bit off. I usually see it like this:
constructor() {
super();
this.state = {
text: '',
storedValue: '',
myArray: '',
};
}
I have a component will use map to render multi checkbox, and each checkbox has a callback function "onPress" get by props, the "onPress" function will setState checked, but now when I click on one checkbox, all checkboxs will be chosed, it cause they all use the same state, the goal I wanna choose each checkbox what I just ckick on, I know I can write many state different "onPress" function for each checkbox, but it looks stupid, I will add more checkbox in the future, What's the best and flexiable way to solve the task?
import React, { Component } from 'react'
import { View } from 'react-native'
import { CheckBox } from 'react-native-elements'
const styles = {
CheckBox: {
borderBottomWidth: 0.3,
borderBottomColor: 'gray'
},
checkBox : {
backgroundColor: "#ffffff",
borderWidth: 0
},
text: {
flex: 0.95,
backgroundColor: "#ffffff"
}
}
const languages = ["中文","英文","日文","韓文"]
class Language extends Component {
constructor(props) {
super(props);
this.state = { checked: false };
}
onPress = () => {
this.setState({ checked: !this.state.checked })
}
renderlanguages = () => {
return languages.map((langauge) => {
return(
<View key = { langauge } style = { styles.CheckBox }>
<CheckBox
title = { langauge }
iconRight
containerStyle = { styles.checkBox }
textStyle = { styles.text }
checkedColor = 'red'
checked = { this.state.checked }
onPress = { this.onPress }
/>
</View>
)
})
}
render(){
return(
<View>
{ this.renderlanguages() }
</View>
)
}
}
export default Language;
The behavior is choose all checkbox even though I only choose one now.
You can just pass the langauge (note this is probably a typo for language) variable to the function and us it to identify which one is being checked
onPress = (langauge) => {
this.setState({ [langauge]: { checked: !this.state[langauge].checked } })
}
renderlanguages = () => {
return languages.map((langauge) => {
return(
<View key = { langauge } style = { styles.CheckBox }>
<CheckBox
title = { langauge }
iconRight
//component = { () => {return <TouchableOpacity></TouchableOpacity>}}
containerStyle = { styles.checkBox }
textStyle = { styles.text }
checkedColor = 'red'
checked = { this.state[langauge].checked }
onPress = { () => this.onPress(langauge) }
/>
</View>
)
})
}