I am trying to make simple button navigation from one view to other ( I'm yet unsure that does this is called view or not ).
For example I have Featured.js as
var SearchPage = require('./Search');
class Featured extends Component {
showSearchPage(){
console.log('showing search page');
this.props.navigator.push({
title: "Search",
component: SearchPage
});
}
render() {
return (
<TouchableHighlight onPress={() => this.showSearchPage()}>
<View style={styles.row}>
<Text style={styles.label}>Open Search Page</Text>
</View>
</TouchableHighlight>
);
}
}
module.exports = Featured;
Then have Search.js as another Class very much like the Featured.js . How can i create a button in the view which on tap open Search.js view.
Currently I am getting "Can not read property push of undefined".
How to define navigator or there is other simple way to navigate?
NOTE: I don't want to make TabBar navigation.
So basically you have an app page which render either subviews depending on user actions.
First of all I suggest you use state instead of props for what you are doing (it's dynamic not static).
var SearchPage = require('./Search');
var Initial = require('./Initial');
var AnotherSubView = // ...
class Featured extends Component {
getInitialState: function() {
title: "initial",
component: <Initial/>
return({title:title, component:component});
}
showSearchPage(){
console.log('showing search page');
this.setState({
title: "Search",
component: <SearchPage/>
});
}
render() {
var title = this.state.title;
var component = this.state.component;
return (<div>
<TouchableHighlight onPress={() => this.showSearchPage()}>
<View style={styles.row}>
<Text style={styles.label}>Open Search Page</Text>
</View>
</TouchableHighlight>
{component}
</div>);
}
}
module.exports = Featured;
Use getInitialState to load your first/landing subview. Then change your component on click.
By the way the props was undefined because you didn't define it =p. And you should use setProps. Anyway I think this was not the right was to proceed but so you know.
Hope it helps!
Related
I want my value to change on the screen when button is pressed. It does change the variable value behind the scenes but has no effect for the outdated value shown on the screen.
export default class App extends Component {
render() {
this.state = {
myVariable: 'egs'
}
const changeValue = () => {
this.state.myVariable = "CHANGED??!!"
}
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
I expect to update value to the changed one instead of outdated one.
Move state initialization outside of render as well as the changeValue method
You also cannot mutate statue directly, instead use setState()
This should work:
export default class App extends Component {
state = {
myVariable: 'egs'
}
changeValue = () => {
this.setState({myVariable:"CHANGED??!!"})
}
render() {
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
this.state.myVariable = "CHANGED??!!"
change to
this.setState({ myVariable: "CHANGED??!!" })
I'm using react-native-highlight-words to highlight hashtagged words in my react-native app. It highlights required words properly but I want to make it clickable too which is not provided by this library. Means when I will click #positivewibes word, it redirect me to another page.
I've uploaded the image for reference here.
My Code
import Highlighter from 'react-native-highlight-words';
export default class LikeComponent extends Component {
constructor(props) {
super(props);
this.state = {
highlightWordArray: []
};
}
componentDidMount() {
postText = this.props.postData.details;
var regexp = new RegExp('#([^\\s]*)','g');
postText = postText.match(regexp);
if(postText != null) {
this.setState({highlightWordArray: postText});
}
}
render() {
return (
<Highlighter
highlightStyle={{color: 'red'}}
searchWords={this.state.highlightWordArray}
textToHighlight= {this.props.postData.details}
/>
)}
}
Any help is appreciated. Thank you.
You can fork and modify the library code by providing an additional prop - onPress in the file as
<Text
onPress={props.onPress}
key={index}
style={chunk.highlight && highlightStyle}
>
{text}
</Text>
and later use it as
<Highlighter
...// other props
onPress={// your redirect instance}
/>
In my app i have a function outside 'export' which return a view, on click event of a button inside view another function is invoked which defined inside 'export'.
While clicking button error is received -
this4.myFunc is not a function.
screenshot attached below - error screen shot
below is my code -
export default class RosterView extends Component{
constructor(props){
super(props)
this.state={
....
}
render () {
mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
<AddPlayersToRosterList
data={item}/>
</View>
}>
</List>
);
}
isExist = (item) =>{
//My Code
return flag;
}
addRemovePlayer = (data) => {
//My Code
}
}
const AddPlayersToRosterList= ({data}) => (
(!mContext.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple style={MainView.PlayerAddRemoveContainer} onPress={()=> this.addRemovePlayer(data)}>
</Ripple>
</View>
)
when press button inside AddPlayersToList, this.addRemovePlayer() shows error.
please provide your help how to fix this problem.
Thanks in advance.
Hi you have many errors here. i tried to rewrite your code. try this here. and let me know if that helps. delete the whole AddPlayersToRosterList functional component that you wrote at the end. and rewrite it inside the component RosterView as a function.
The problem is, if you try to use functions that were not declared inside functional components, those components dont know the functions you are trying to call. In the case of const AddPlayersToRosterList you call the functions isExist(data) and this.addRemovePlayer(data), that were declared inside RosterView, but not inside AddPlayersToRosterList.
// add this function inside RosterView
AddPlayersToRosterList = (data) => {
(!this.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple
style={MainView.PlayerAddRemoveContainer}
onPress={() => this.addRemovePlayer(data)}>
</Ripple>
</View>
}
render (){
var mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
{this.AddPlayersToRosterList(item)// make sure you call the function here}
</View>
}>
</List>
);
}
you could just pass as props the functions you need to your functional component without delete anything. but it would be cost more memory and compution power that you probably need depending of how many props you want to pass.
const AddPlayersToRosterList= ({data, isExist, mContext, addRemovePlayer}) => (
(!mContext.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple
style={MainView.PlayerAddRemoveContainer}
onPress={()=> this.addRemovePlayer(data)}
>
</Ripple>
</View>
)
and in your render method
render () {
mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
<AddPlayersToRosterList
data={item}
isExist={this.isExist}
mContext={mContext}
addRemovePlayer={this.addRemovePlayer}
/>
</View>
}>
</List>
);
}
I am using react native and I have a situation where I navigate to a new component using react navigation v2 stack navigator. The user then presses an option and goes back to the original screen they were at with updated information.
My question is how do change the state of the previous screen so it shows the information the user selected?
ShowFruitPage.js
This page shows a list of fruits that the user picked.
export default class ShowFruitPage extends Component{
constructor(){
super();
this.state = {
List: [{Fruit: apple}]
}
}
render(){
return(
<View style={styles.ViewStyle}>
<FlatList
data={this.state.List}
renderItem={({item}) =>
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple('grey')}
onPress={() => this.props.navigation.navigate('AddFruit',
{
List: this.state.List
})}
<View style={styles.ListView}>
<Text>{item.Fruit}</Text>
</View>
</TouchableNativeFeedback>
}
/>
</View>
)
}
}
AddFruit.js
This page shows a list of available fruits the user can pick.
When the user picks from this list I want to update the list on the ShowFruitPage.
export default class AddFruit extends Component{
constructor(){
super();
this.state = {
FruitList: [{Fruit:orange}, {Fruit: pear}]
}
this.pickFruit = this.pickFruit.bind(this);
}
pickFruit(Fruit){
//Add the picked fruit to the ShowFruitPage state List
//Then Navigate back to ShowFruitPage
this.props.navigation.navigate('ShowFruitPage')
}
render(){
return(
<View style={styles.ViewStyle}>
<FlatList
data={this.state.FruitList}
renderItem={({item}) =>
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple('grey')}
onPress={() => this.pickFruit(item)}
<View style={styles.ListView}>
<Text>{item.Fruit}</Text>
</View>
</TouchableNativeFeedback>
}
/>
</View>
)
}
}
Just as you did in ShowFruitPage.js with List, you could navigate back with some state, i.e.
this.props.navigation.navigate('ShowFruitPage', { Fruit });
to make { Fruit } available on navigation.state.params when you navigate back to ShowFruitPage.
Another possibility (I think) is to provide a callback when you navigate to AddFruit that can set the data on the ShowFruitPage allowing you to then just call navigation.goBack():
setFruit = fruit => {
this.setState({ FruitList: [...this.state.FruitList, fruit] });
}
this.props.navigation.navigate('AddFruit', { setFruit: this.setFruit });
And then:
pickFruit(Fruit){
const { navigation } = this.props;
navigation.state.params.setFruit(Fruit);
navigation.goBack();
}
An alternative and heavier solution, would be to implement some state management such as redux so that the data becomes independent of the individual page components.
I'm attempting to write a function to remove a React Native component (named "Card") from the DOM on-click, then append a new "Card" of the same class with different properties. For example, both Cards have background colors. If the first Card is green, the second Card, which should have a blue background, will inherit the green background of the original Card.
The Cards receive their background color passed as props, like so:
class Card extends Component {
constructor(props) {
super(props);
this.state = {
style: {
backgroundColor: this.props.card.backgroundColor
}
};
}
render() {
return (
<TouchableHighlight style={this.state.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
}
The main component looks like this:
class SetProject extends Component {
constructor(props) {
super(props);
this.state = {
cardArray: [{backgroundColor: 'green', img: require('~/SetProject/cardImages/ovals/1-red-empty-oval.png')}]
}
}
removeCard(){
let emptyArray = [];
this.setState({cardArray: emptyArray});
}
changeCard(){
// let emptyArray = [];
// this.setState({cardArray: emptyArray});
let newCardArray = [{backgroundColor: 'red', img: require('~/SetProject/cardImages/ovals/1-purple-shaded-oval.png')}]
this.setState({cardArray: newCardArray});
}
render() {
let cardElementArray = this.state.cardArray.map(theCard => {
return (
<Card card={theCard}></Card>
);
});
return (
<View>
<View>
{cardElementArray}
</View>
<TouchableHighlight>
<Text onPress={this.removeCard.bind(this)}>Remove Card</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text onPress={this.changeCard.bind(this)}>Change Background</Text>
</TouchableHighlight>
</View>
);
}
}
So I've got two buttons: removeCard, which works great, and changeCard. If I press "Remove Card" and then press "Change Card," I see the exact results I'm looking for. The card is removed and is replaced by a new one. However, if I comment in these lines in changeCard:
// let emptyArray = [];
// this.setState({cardArray: emptyArray});
and press "Change Card" without pressing "Remove Card," the new Card has a new image but it keeps the background color of the previous Card. This also happens if I call this.removeCard() from changeCard.
In summary, I'd like to be able to perform the behavior of both of these functions simultaneously, but I'm only able to remove a Card and add a new, correctly rendered Card if I press both buttons separately.
Any ideas would be much appreciated!
Here you're using props for setting image but not setting style. You can use props as well. You have set the style in constructor. Then you want to change style but constructor is not called again but creating a new object.
You can use props setting styl as well
render() {
return (
<TouchableHighlight style={this.props.card.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
For better implementation in case properties of card gets more complex add an id property to card. You can use componentWillReceiveprops by this way unnecessary renders are neglected as well.
[{id:'1', backgroundColor: 'red', img:
require('~/SetProject/cardImages/ovals/1-purple-shaded-oval.png')}]
class Card extends Component {
constructor(props) {
super(props);
this.state = {
style: {
card: this.props.card
}
};
}
componentWillReceiveProps(nextProps){
if(nextProps.card.id != this.state.card.id)
{
setState({card:nextProps.card})
}
}
render() {
return (
<TouchableHighlight style={this.state.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
}
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
Don't you get warning about missing keys in array? Use unique identifier (or it's index in array as last resort) for each card, and use it to set key prop on each item in array. This way, when card in array changes, react can re-render it, because it's a new card to it.
let cardElementArray = this.state.cardArray.map(theCard => {
return (
<Card key={theCard.id} card={theCard}></Card>
);
});
Read more about keys here in React docs.