Is it possible to setState on other function tag? - react-native

Here is my code,
This code is working fine use "setState" to set new variable in componentDidMount tag.
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
name: "peter",
}
}
componentDidMount(){
this.setState({name:"sam"});
}
render(){
return (
<View>
<Text>
{this.state.name}
</Text>
</View>
)
}
}
But I want to create a new function to set it.
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
name: "peter",
}
}
changename(){
this.setState({name:"sam"});
}
render(){
this.changename();
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
{this.state.name}
</Text>
</View>
)
}
}
It displays
Minified React error #185;
Error
componentDidMount is work,
but it is not working on my own function tag
any idea how to fix it
Thank you very much.

You have put an unconditional state change in render. Because of that your render triggers a state change which triggers a re-render which again triggers a state change - An infinite loop.
You could put some sort of condition on which to trigger a state change for example:
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {name: "peter"}
}
changename(){ this.setState({name:"sam"}); }
render(){
if(this.state.name==='peter')
this.changename();
return (
<View>
<Text>{this.state.name}</Text>
</View>
)
}
}

Related

my Button cannot change a state in another react native component

Why does the following code not work? In this test I simply try to show a state of the component Board, when the Button is clicked. But I get a TypeError: undefined is not an object.
var board = (<Board/>);
return (
<View>
{ board }
<Button
title="Press me"
onPress={() => Alert.alert(board.state.lastRefresh)}
/>
</View>
);
};
The Board component has this constructor:
constructor(props) {
super(props)
this.state = {
lastRefresh: Date(Date.now()).toString(),
}
...
If your Board component is something like this:
import PageTwo from 'PageTwo';
export default class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
lastRefresh: Date(Date.now()).toString(),
}
}
render() {
return (
<View>
<PageTwo lastRefresh={this.state.lastRefresh}>
</PageTwo>
</View>
)
}
}
You can access your props by this way from PageTwo component:
export default class PageTwo extends React.Component {
render() {
return (
<View>
<Button
title="Press me"
onPress={() => Alert.alert(this.props.lastRefresh)}
/>
</View>
)
}
}

Changing state from a child component

So, I've just figured out today that only changing state in a React Native app triggers a re-render of the component. I'm changing state, but I'm doing it from a child component, and it seems to getting stuck in some loop, and () => { this.setState({current_time:'whatever'}) doesn't seem to do anything at all. How can I change my App.js's current_time in state from TimePicker.js?
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker />
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity>
<View style={s.contain} onPress={
/*
set this.state.current_time in parent to the actual current time
this.setState({current_time:'changed'}) seems to cause an infinite loop?
() => { this.setState({current_time:'changed'}) } doesn't seem to do anything
*/
}>
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
ShowTime.js
class ShowTime extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<View style={s.contain}>
<Text>{this.props.current_time}</Text>
</View>
)
}
};
Create a function in App.js and pass it as prop to TimePicker Component and the purpose of this function should be to setState . e.g
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
currentTimeHandler = (newCurrentTime) => {
this.setState({current_time: newCurrentTime});
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker getTime={ this.currentTimeHandler }/>
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity onPress={() => this.props.getTime('changes will be passed here')}>
<View style={s.contain} >
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
The reason is the setState only set the existing states locally in the js file. that would be your Timepicker.
In your case TimePicker is a child(or sub branch) of App (Your app stores your state, by your current build, and will never be changed by a child). You will need create two functions one in TimePicker and another App. TimePicker will handle the data and send it, via prop, the App will receive the prop and then trigger another function to setState.
Pass data from child to parent in React
This is the best one i can find.
Best read this as well:
https://reactjs.org/docs/react-component.html
It does say, setState only affect to local states, your state you want to set is not local.

render is not calling on state change

export default class TopMiddleLoadingView extends React.Component{
size = 66;
constructor(props) {
super(props);
this.state = {
fill : 99,
timeLeft : props.timeLeft
}
}
onPress(){
this.setState = {
...this.state, fill:10
}
}
componentWillUpdate(nextProps, nextState) {
alert("componentWillUpdate");
}
render(){
alert("render")
return(
<View style={{width:this.size, height:this.size}}>
<View style={[styles.absoluteCenter,{zIndex:999}]}>
<Thumbnail source={Images.seaImg}></Thumbnail>
</View>
<Text>{this.state.fill}</Text>
<Button
style={{width:50,height:50,backgroundColor:"red",position:"absolute",zIndex:999}}
onPress={this.onPress}
></Button>
</View>
);
}
}
on button press, onPress function is clicked, and change the state of the component, but the render function is not calling.
I am very new to react native. Any idea?
You aren't changing the state either let alone re render. And if you want to re render then you should change state using setState() method. Also, you need to refresh you javascript this knowledge
export default class TopMiddleLoadingView extends React.Component{
size = 66;
constructor(props) {
super(props);
this.state = {
fill : 99,
timeLeft : props.timeLeft
}
}
onPress = () => {
this.setState({fill:10})
}
componentWillUpdate(nextProps, nextState) {
alert("componentWillUpdate");
}
render(){
alert("render")
return(
<View style={{width:this.size, height:this.size}}>
<View style={[styles.absoluteCenter,{zIndex:999}]}>
<Thumbnail source={Images.seaImg}></Thumbnail>
</View>
<Text>{this.state.fill}</Text>
<Button
style={{width:50,height:50,backgroundColor:"red",position:"absolute",zIndex:999}}
onPress={this.onPress}
></Button>
</View>
);
}
}
Render method is called whenever there is change in state of that component. You should use this.setState({...this.state, fill:10} for updating state of the component. This must cause render function to fire again, if there is not any other logic written inside shouldComponentUpdate() for conditional rendering.
Hope this helps. Also check out,
What the difference of this.state and this.setstate in ReactJS?

loading/importing contents of Modal from another js (class) file in react-native

My modal displays an input form. I want to import contents of my Modal from another js file for keeping the main code shorter. I am actually able to import contents of my Modal from another class file by calling component's class name as jsx tag, but in this case I cannot pass state variables of main component to inner component of the modal or vice versa. And, I don't know if it is possible to receive data from the modal in this case. I know that I could use navigator with passProps, but I want to use just a modal for this purpose. For instance:
this is main Component:
class Main extends React.Component {
constructor(props){
super(props);
this._showAddNewModal = this._showAddNewModal.bind(this);
this.state = {
addNewShow: false,
mytext: '' // this should be updated through Modal.
}
}
render(){
return (
<TouchableHighlight onPress={() => {this._showAddNewModal();}}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal visible={this.state.addNewShow}>
<MyModalContents />
</Modal>
);
}
_showAddNewModal(){
this.setState({addNewShow: true});
}
}
this is the component to be displayed in the modal:
class MyModalContents extends React.Component { // extends Modal?
constructor(props){
super(props);
this.state = {mytext: ''}
}
render(){
<View>
<TextInput onChangeText={(text) => this.setState({mytext: text})} />
</View>
}
}
I can't even close the modal because the state of 'addNewShow' is not accessible from MyModalContents. Any help will be appreciated.
You can pass props to a child component by cloning it with React.cloneElement. Here's an example of how you could use it with your modal:
class Main extends React.Component {
constructor(props){
super(props);
this.state = {
mytext: '' // this should be updated through Modal.
}
}
_showAddNewModal(){
this.refs.modal.show();
}
render(){
return <View>
<TouchableHighlight onPress={this._showAddNewModal}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal parent={this} ref="modal">
<MyModalContents />
</Modal>
</View>
}
}
Modal
class Modal extends React.Component {
constructor(props){
super(props);
this.state = {
visible: false,
}
}
show() {
this.setState({visible: true});
}
close(){
this.setState({visible: false});
}
render(){
return <View style={{opacity: this.state.visible ? 1 : 0}} pointerEvents={this.state.visible ? 'auto' : 'none'}>
{/* can pass props with second argument */}
{React.cloneElement(this.props.children, {
parent: this.props.parent,
modal: this
})}
</View>
}
}
MyModalContents
class MyModalContents extends React.Component {
constructor(props){
super(props);
}
_updateModalState() {
const self = this;
// will update the "Main" component state as props are passed through modal
this.props.parent.setState({myText: 'Updated Text!'}, () => {
self.props.modal.close();
});
}
render(){
return <View>
<TouchableHighlight onPress={this._updateModalState}>
<Text> Update Modal State </Text>
</TouchableHighlight>
</View>
}
}

React native - Binding event in row of ListView

I cannot find the correct way in order to trigger the event from the class based definition under the row of the list view. Here is what i come so far
class SampleApp extends React.Component {
constructor(props){
super(props)
this.state = {
dataSource: ds.cloneWithRows(this._partners()),
}
// this._click = this._click.bind(this);
}
_click() {
console.log('clicked');
}
_renderRow(rowData) {
return (<TouchableHighlight onPress={() => {this._click();}}>
<Text style={{ fontSize:18 }}>{rowData}</Text>
</TouchableHighlight>);
}
render() {
console.log('Partners: ', this._partners() )
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={ this._renderRow } />
</View>
);
}
}
this inside onPress is not referred to react component. How can I fix it ? This is the react playground link https://rnplay.org/apps/Xd-l3w
Try this.
constructor(props){
super(props)
this.state = {
dataSource: ds.cloneWithRows(this._partners()),
}
this._renderRow = this._renderRow.bind(this);
}
_renderRow() doesn't contain the scope. Rebinding it fixes the issue.
onPress={this._click} will also work instead of putting the this._click in another function.
Here's a fork of your code.