i just start to learn react native i want to make ui like this,
i want the buttons on the image work like radio button, so user just can choose a button and change the button style choosed by user, and bellow is my code
class ButtonOption extends Component {
constructor(props) {
super(props);
this.state = {
data : [],
active : 0
};
}
loadButton(temp){
let result = [];
for (let i =0;i<temp.length;i++){
if(i==this.state.active){
result.push(
<View key={i} style={buttonOption.main}>
<TouchableOpacity style={buttonOption.tabActive} onPress={()=>{this.setState({active:i});alert(this.state.active)}}>
<Text style={buttonOption.labelActive}>{temp[i]}</Text>
</TouchableOpacity>
</View>)
}else{
result.push(
<View key={i} style={buttonOption.main}>
<TouchableOpacity style={buttonOption.tab} onPress={()=>{this.setState({active:i});alert(this.state.active)}}>
<Text style={buttonOption.label}>{temp[i]}</Text>
</TouchableOpacity>
</View>)
}
}
return result;
}
componentDidMount(){
this.setState({data:this.loadButton(this.props.arrButton)})
}
render() {
return (
<View style={{flexDirection:'row',padding:10}}>
{this.state.data}
</View>
);
}
}
export default ButtonOption;
on code above i was try to make button with looping, in looping function i use active as a state for check active button, and add function onPress so everytime user click button, active state will change, but when i run and choose button the active state won't change, what is wronge with my onPress code, can someone help please?
I think I might know the answer, You have generated the view using this.loadButton and saved it in this.state.data. This is done one time only. when the render method is called. It is expecting a new view based on states but this.state.data is not changing since you create it in componentDidMount. What you need to do is to call this.loadButton(this.props.arrButton) in render method. this will create new view every time render method is called.
render() {
return (
<View style={{flexDirection:'row',padding:10}}>
{this.loadButton(this.props.arrButton)}
</View>
);
}
This might do it, If you still have any error, please report.
Related
This is my function for rendering items in a flatlist
renderItem = ({ item }) => {
var integer = Number(item.key)
return (
<View>
<Text style={styles.row}>
{item.text}
</Text>
<View style={{flexDirection:'row'}}>
{this.createButtonYes(integer)}
{this.createButtonNo(integer)}
{this.answer(this.state.buttonStates[integer])}
</View>
<Text >__</Text>
</View>
)
}
And the problem I am facing is the function this.answer is not being called when the state of buttonStates changes
answer = (val) => {
if(val){
return(
<Text style={{fontSize:20}}>YES</Text>
)
}else if(val==false){
return(
<Text style={{fontSize:20}}>NO</Text>
)
}else{
return(
<Text style={{fontSize:20}}>Not Answered</Text>
)
}
}
I assumed that every time the state changes the function would be called but that does not seem to be the case, so does anyone have a solution? What I want is whenever the buttons are pressed the state will change and then this.answer will take the changed state and display what it has to accordingly.
Thanks
EDIT:
Code for the button:
buttonYesHelp = num =>{
const newItems = [...this.state.buttonStates];
newItems[num] = true;
return newItems
}
createButtonYes = (num) => {
return(
<TouchableOpacity style={styles.buttonYes}
onPress =
{
()=> {{this.setState({ buttonStates:this.buttonYesHelp(num) })}}
}>
<Text style={styles.buttonTextStyle}>YES</Text>
</TouchableOpacity>
)
}
num is the index of the thing I want to change in the list
EDIT:
I have tried multiple different things but the problem I keep running into is that when I render the button I want it to react to a state variable but it never seems to change based on the state even when the state is changing.
For example, in this.answer I assumed that it would return the text based on the state of buttonStates but it seems to only account for the initial state and nothing after
I was able to achieve this in a different piece of code with identical syntax but for some reason this is not working
Im using a flat list on 2 different screens.
On the EventListScreen:
this is the main screen and should display all events.
and on the 2nd page UserProfile.js this page should only display that users events.
in both flat lists I'm using a pure component stored in a seperate class, to where the flat lists are i.e
My Question is, I want to display an "Edit" button on the Event.js child component only if the User is on the
UserProfileScreen.js
I have looked up a lot of example but cant really find any that show how to do it
with a child pure component like I'm doing.
Any Help would be greatly appreciated! Thank you
EventListScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
{...item}
/>}
/>
Event.js
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
}
You don't need additional properties.
We can assume that the "Edit" button should be available when openEditEvent prop is defined.
Condition in event (using convertion to bool, false for undefined):
<CardSection>
<Text>{this.props.eventName}</Text>
{!!this.props.openEditEvent &&
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
}
</CardSection>
Use propTypes to define openEditEvent prop as a function, optional (not required).
If I understand your problem correctly an option to solve this problem would be to pass a boolean "showable prop" to show the edit button only when required:
EventListScreen.js (Stays the same, we don't show the edit button here)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js (we add the shouldShowEditButton prop to event in order to show the button)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
shouldShowEditButton
{...item}
/>}
/>
Event.js (We add some propTypes and defaultProps to handle the new prop, it won't show the edit button if not specified)
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
{this.props.shouldShowEditButton && <Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>}
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
...
...
);
...
}
}
// We add some default propTypes and definitions
Event.propTypes = {
shouldShowEditButton: PropTypes.bool
};
Event.defaultProps = {
shouldShowEditButton: false
};
In this way you're only showing the edit button for the components that have the prop shouldShowEditButton defined, and because its default value is defined as false, the components that don't have the property will behave in the same way they were before.
I have a ListView component in which I need to change the background color of each row independently according to an onPress event.
<View style = {[styles.checkBox, {backgroundColor: this.state.button[rowID]? '#62C6C6':'transparent'}]}/>
Because I don't know how many rows will be rendered, but at most there'll be 4, so I declared an array state button as [false, false, false, false] and change element value according to the row. For example when I press the first row, with rowID is 0, I will set the state of button to be [true, false, false, false]. In this method, the state for button is changed, but the UI does not rerender the background color .
I think the logic here is correct(ish?), is there any way I can get the expected result or there's a smarter way to achieve this
A suggestion will be to create your own component to render inside each row and only changing the background of that component when clicked. Which then means you don't need to keep an array of the state the state will be in each component itself.
This will be your component:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
backgroundColor:'transparent'
}
}
render() {
return (
<View style={{ backgroundColor: this.state.backgroundColor}}>
<TouchableOpacity onPress={this.changeColor.bind(this)}>
<Text>This is my Component</Text>
</TouchableOpacity>
</View>
);
}
changeColor(){
this.setState({
backgroundColor:'#62C6C6'
});
}
}
Then in you renderRow you can call your component:
renderRow(rowData){
return(
<View>
<MyComponent/>
</View>
)
}
For ListView dataSource needs to be reset again to trigger changes.
Make dataSource as state, as shown in the sample
https://facebook.github.io/react-native/docs/listview.html
I have the following set up, with all the methods with .bind(this) in the constructor. So the user enters in username and password in the inputs and get updated in state, and the component gets re-rerendered and newly updated state this.props.username and this.props.password get passed down. I would then want to pass them into an action creator called this.props.registerUser() once Register button is clicked.
So I was wondering, what's the right practice to pass in the newly updated props to an action creator?
For example
Is it _handleRegister(this.props.username, this.props.password) then this.props.registerUser(this.props.username, this.props.password)? Or simply this.props.registerUser(this.props.username, this.props.password)? Or a combination of this._handleRegister(this.props.username, this.props.password) and former?
_handleRegister() {
this.props.registerUser()
}
render() {
return (
<View>
<TextInput
placeholder={'Username'}
onChangeText={...}
value={this.props.username}
/>
<TextInput
placeholder={'Password'}
onChangeText={...}
value={this.props.password}
/>
<TouchableHighlight onPress={this._handleRegister}>
<Text>Register</Text>
</TouchableHighlight>
</View>
)
}
}
Thank you
You don't need to pass prameters to _handleRegister
_handleRegister() {
const { username, password, registerUser } = this.props;
registerUser(username, password);
}
Additional tip: you can skip return keyword by doing:
render() (
<View>
...
</View>
)
I've been trying to get a UITableView equivalent in React-Native. The screen looks like this (work in progress):
The code for this is quite primitive at the moment:
class SettingsView extends Component {
render() {
return(
<View style={styles.container}>
//more View code
//example of a cell
<TouchableHighlight style={styles.tableViewCell}>
<Text style={styles.cellLabel}>Log Out</Text>
</TouchableHighlight>
</View>
);
}
}
It works fine, I've been trying to create an accessory - an > indicator - for all my cells. Whilst doing that, I stumbled upon a way to create custom component via this code:
class TableViewCell extends Component {
render() {
return (
<TouchableHighlight style={styles.tableViewCell}>
<Text style={styles.cellLabel}>Log Out</Text>
</TouchableHighlight>
);
}
}
Next, I replaced the initial block of code and I came out with this:
class SettingsView extends Component {
render() {
return(
<View style={styles.container}>
//more View code
//example of a cell
//Replaces the previous block of TouchableHighlight
<TableViewCell/>
</View>
);
}
}
Wow. To a native Swift developer that has barely any experience with HTML and JavaScript, this is amazing. I immediately went on quest in an attempt to find out how I might make this reusable. Currently, TableViewCell is hardcoded to have the text "Log Out". Ideally I want to be able to supply the text as an argument for the constructor. This is where I got stuck. Here's what I've tried so far:
Use getAttribute to see if I could extract an attribute that I would pass in whilst declaring the TableViewCell tag.
//when declaring a cell on the screen's render
<TableViewCell titleText="About"/>
//tableViewCell component
render() {
return(
<TouchableHighlight ...>
<Text>{this.getAttribute("titleText")}</Text>
</TouchableHighlight>
);
}
I couldn't get a reference to the titleText that I've declared as part of the tag. Any ideas?
I could be wrong, but I'm pretty sure this is what you need. You can pass properties to components and receive them as this.props:
// when declaring a cell on the screen's render
<TableViewCell titleText="About"/>
// tableViewCell component
render() {
return(
<TouchableHighlight ...>
<Text>{this.props.titleText}</Text>
</TouchableHighlight>
);
}