I can't update state in child component - javascript

i wanna change state value in child component but i getting always 'this.setState is not a function ' error
Parent Component
`
export default class Todo extends Component {
constructor(props){
super(props)
this.state = {
propBottomMenu : false
}
this.bottomRef = React.createRef()
};
checkClose(){
this.setState({propBottomMenu : false})
}
render() {
return (
<>
// other codes
<TouchableOpacity
onPress={() => this.setState({propBottomMenu : false})}
style={styles.addTask}
>
<FontAwesomeIcon icon={ faPlus } size={25} color={'#fff'} />
</TouchableOpacity>
{this.state.propBottomMenu ?
<BottomMenu bSheetRef={this.bottomRef} checkClose={this.checkClose} style= {styles.bottomMenu} />
: null}
</>
)
}
}
`
Child Component :
`
export default class BottomMenu extends Component {
constructor(props){
super(props)
this.bottomRef = this.props.bSheetRef
}
render() {
return (
<>
<BottomSheet
ref={this.bottomRef}
snapPoints={[ '40%', '60%', '90%']}
index={1}
enablePanDownToClose={true}
onChange={(index)=>{ index < 0 && this.props.checkClose() }}
>
// other codes
</BottomSheet>
</>
)
}
}
})
`
checkClose() function working but i can't update state
Error : this.setState is not a function

Solution :
For the function to work we must use bind or call it as arrow function
constructor(props){
super(props)
this.checkClose = this.checkClose.bind(this); // this line
this.state = {
propBottomMenu : false
}
this.bottomRef = React.createRef()
};
Jsx:
<BottomMenu bSheetRef={this.bottomRef} checkClose={this.checkClose} style={styles.bottomMenu} />

Related

this2.props.addToList is undefined, List creation error

Diet.js
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.addToList = this.addToList.bind(this);
}
addToList(item) {
const list = [...this.state.list, item];
this.setState({ list });
}
render() {
<FoodCreate addToList={this.addToList} />
return (
<FoodList items={this.state.list} />
)}
FoodCreate
export class FoodCreate extends Component {
constructor(props) {
super(props);
this.state = {
FoodName: "",
calories: 0,
};
}
render() {
return (
<Button transparent>
<Icon
name="checkmark"
style={{ fontSize: 25, color: "red" }}
onPress={() => this.props.addToList(FoodName, calories)}
/>
</Button>
<TextInput
placeholder="Food Name"
placeholderTextColor="white"
style={styles.inptFood}
value={FoodName}
onChangeText={(FoodName) => this.setState({ FoodName: FoodName })}
/>
<TextInput
placeholder="Calories"
placeholderTextColor="white"
style={styles.inptMacros}
keyboardType="numeric"
value={calories}
maxLength={5}
onChangeText={(calories) => this.setState({ calories: calories })}
/>
FoodList
export class FoodList extends Component {
render() {
return (
<Content>
<List>
<ListItem itemDivider>
<Text>Food</Text>
{this.props.items.map((item, index) => {
return (
<ListItem key={index}>
<Text>{item.FoodName}</Text>
<Text>{item.calories}</Text>
</ListItem>
);
})}
</ListItem>
</List>
</Content>
);
}
}
export default FoodList;
Hi, I'm new to programming and React Native, so I'm trying to create a Grocery List by letting the user type FoodName and Calories and pressing the Icon: Check in FoodCreate page, and List it in the FoodList page, at the moment when I run the code gives me back an error: _this2.props.addToList is not a function, I've tried many solutions but I'm not sure where the error is.
class FoodCreate extends Component {
render() {
return (
<Button title="aaa" onPress={() => this.props.addToList('name')}></Button>
);
}
}
export default class Diet extends Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.addToList = this.addToList.bind(this);
}
addToList(item) {
const list = [...this.state.list, item];
this.setState({list});
}
render() {
return <FoodCreate addToList={this.addToList} />;
}
}
I use the above code and didn't get the error
But I think you can have a better code
Don't use this.addToList = this.addToList.bind(this);, you can convert addToList to arrow function and remove this line
addToList = item => {
const list = [...this.state.list, item];
this.setState({list});
};

getting the value of child component

I'm trying to get the value of child component yet not successful. Here what I am working on ...
import React from "react";
import Tooltip from "rc-tooltip";
import Slider, { Range } from "rc-slider";
const Handle = Slider.Handle;
const handle = props => {
const { value, dragging, index, ...restProps } = props;
return (
<Tooltip
prefixCls="rc-slider-tooltip"
overlay={value}
visible={dragging}
placement="top"
key={index}
>
<Handle value={value} {...restProps} />
</Tooltip>
);
};
const Slider = props => {
return (
<div>
<div style={{ width: 300, margin: 30 }}>
<p>{this.props.title}</p>
<Slider min={0} max={10} defaultValue={5} handle={handle}/>
</div>
</div>
);
};
export default Slider;
Main App.js
import Slider from '.....'
class App extends Component{
constructor(props){
super(props);
this.state = {
val: 0
}
}
render() {
return(
<Slider onChange={this.state.value} />
)
}
}
I am looking to get the value to be updated to this App.js state as the slider is being dragged. onChange is not updating the state. How should I modify so that slider value gets updated on this.state.value.
The Slider component from rc-slider has an onChange prop event which is a function. You need to pass this method to slider and update the state instead of just passing the state value
import React from "react";
import Tooltip from "rc-tooltip";
import Slider, { Range } from "rc-slider";
const Handle = Slider.Handle;
const handle = props => {
const { value, dragging, index, ...restProps } = props;
return (
<Tooltip
prefixCls="rc-slider-tooltip"
overlay={value}
visible={dragging}
placement="top"
key={index}
>
<Handle value={value} {...restProps} />
</Tooltip>
);
};
const Slider = props => {
return (
<div>
<div style={{ width: 300, margin: 30 }}>
<p>{this.props.title}</p>
<Slider min={0} max={10} defaultValue={5} onChange={props.onChange} handle={handle}/>
</div>
</div>
);
};
export default Slider;
class App extends Component{
constructor(props){
super(props);
this.state = {
val: 0
}
}
onChange=(value) => {
this.setState({val: value});
}
render() {
return(
<Slider onChange={this.onChange} />
)
}
}
Here is the Live code
https://codesandbox.io/s/n9y97y55kp
Let me know if you have any doubts
You just have to pass the event from child to parent component to update the values.
according to rc-slider document, you should pass a function to Slider onChange.
import Slider from '.....'
class App extends Component {
constructor(props) {
super(props);
this.state = {
val: 0
}
}
handleSliderChange = (value) => {
console.log(value) // maybe a string or a object
this.setState({val: value})
}
render() {
return (
<Slider onChange={this.handleSliderChange} />
)
}
}
above code should work

React Native - Execute child function from Parent Button onPress

Disclaimer : I'm new to RN. I have already tested multiple solutions from other similar questions without success so far.
I have a Parent that render two Childrens like this
export default class ParentComponent extends Component {
constructor(props) {
super(props)
}
render() {
return (
<View>
<Foo name="a" ref={foo => {this.foo = foo}} {...this.props} />
<Text>-----------</Text>
<Foo name="b" />
<Text>-----------</Text>
<Button
onPress={this.foo.myFunction()}
title="Start"
color="#841584"
/>
</View>
)
}
}
My class Foo has a function inside it that start some process :
class Foo extends Component {
myFunction(){
// Some stuff here
}
}
How can I call this myFunction for my Child when I press on the Button ? Optionally, is it possible with only one onPress, to call the function for both Child and avoid creating two Button for each Child ?
You can use refs
https://reactjs.org/docs/refs-and-the-dom.html
Example:
class Parent extends Component {
render() {
return (
<View>
<Child ref={instance => { this.child = instance; }} />
<TouchableOpacity onPress={() => { this.child.clicked(); }}>
<Text>Click</Text>
</TouchableOpacity>
</View>
);
}
}
class Child extends Component {
clicked() {
alert('clicked');
}
render() {
return (
<Text>Hello</Text>
);
}
}
Hope it helps
Basically what I did is to call a local function when onPress and change the state of the Parent. I pass this state to the Child during its creation. And since the Child are updated (if needed) when the Parent's state change this do the trick.
export default class ParentComponent extends Component {
constructor(props) {
super(props)
this.state = {
activity: false
}
}
onButtonPress = () => {
this.setState({
activity: !this.state.activity
});
}
render() {
return (
<View>
<Foo name="a" activity={this.state.activity} />
<Text>-----------</Text>
<Foo name="b" activity={this.state.activity} />
<Text>-----------</Text>
<Button
onPress={this.onButtonPress}
title="Start"
color="#841584"
/>
</View>
)
}
}
class Foo extends Component {
myFunction(){
// Some stuff here
}
componentWillReceiveProps(newProps) {
if (newProps.activity === true) {
this.myFunction();
}
}
}
It's better to do myFunction logic inside ParentComponent and setState the data which can be passed into child ie:Foo.
constructor(props) {
super(props);
this.state = {
fooData: initialValue,
}
}
myFunction = () => {
// Some stuff here
this.setState({ fooData: someValue })
}
render() {
return (
<View>
<Foo name="a" data={this.state.fooData} {...this.props} />
<Text>-----------</Text>
<Foo name="b" data={this.state.fooData}/>
<Text>-----------</Text>
<Button
onPress={this.myFunction}
title="Start"
color="#841584"
/>
</View>
)
}
and you can make the changes inside Foo accordingly
class Foo extends Component {
render() {
const { data } = this.props;
return(
//Use data here to make change
)
}
}

perform onclick event in reactjs

I am trying to make an application using reactjs.below is the code which present in my main app.js:
class App extends Component {
return (
<div>
<ExampleTable
header={() => <TopBar/>}
/>
<AddExampleModal/>
<ChartModal/>
<CompatibilityAlert/>
</div>
)
}
}
where Top Bat,AddExampleModal , ChartModal and CompatibilityAlert are loaded from other js files.
Chartmodal contains:
class ChartModal extends Component{
constructor(props){
super(props)
}
render(){
return(
<Modal
onOk={()=>console.log('ok')}
onCancel={()=>console.log('cancel')}
visible={true}
okText={'ok'}
cancelText={'cancel'}
confirmLoading={false}
title="Intent distribution chart"
>
<h1>HOWDY</h1>
<TreeMap
data={chartData}
width={400}
valueUnit={'count'}
/>
</Modal>
)
}
}
Topbar contains :
class TopBar extends Component {
render{
return (
<Button
style={styles.button}
type='primary'
// onClick={() => changechartshow()}
>
Show Graph
</Button>
)
}
}
The thing is that in the app file,i want to toggle the visibility of chartmodal using the button in the topbar.
App
class App extends Component {
constructor() {
this.state = {
isVisible: true
}
}
toggleVisibility = () => this.setState({isVisible: !this.state.isVisible})
render () {
const {isVisible} = this.state;
return (
<div>
<ExampleTable
header={() => <TopBar toggleVisibility =
{this.toggleVisibility.bind(this)}
/>}
<AddExampleModal/>
<ChartModal isVisible={isVisible}/>
<CompatibilityAlert/>
</div>
);
}
}
TopBar
class TopBar extends Component {
render{
return (
<Button
style={styles.button}
type='primary'
onClick={() => this.props.toggleVisibility()}
>
Show Graph
</Button>
)
}
}
ChartModal - Pass the state to visible attribute
class ChartModal extends Component{
constructor(props){
super(props)
}
render(){
return(
<Modal
onOk={()=>console.log('ok')}
onCancel={()=>console.log('cancel')}
visible={this.props.isVisible}
okText={'ok'}
cancelText={'cancel'}
confirmLoading={false}
title="Intent distribution chart"
>
<h1>HOWDY</h1>
<TreeMap
data={chartData}
width={400}
valueUnit={'count'}
/>
</Modal>
)
}
}
You can add a state in your App component and pass an handler to update the state from the TopBar component. Based on this state you can toggle the visibility of ChartModal.
class App extends Component {
state = {
isVisible: true
}
toggleVisibility = () => {
this.setState(prevState => ({isVisible: !prevState.isVisible}))
}
return (
<div>
<ExampleTable
header={() => <TopBar toggleVisibility={this.toggleVisibility}/>}
/>
<AddExampleModal/>
{this.state.isVisible ? <ChartModal/>: null }
<CompatibilityAlert/>
</div>
)
}
}
Now in your TopBar you will call this function as
class TopBar extends Component {
render{
return (
<Button
style={styles.button}
type='primary'
onClick={() => this.props.toggleVisibility()}
>
Show Graph
</Button>
)
}
}
Read the React docs here on Lifting the state up for a detailed explanation

how bind correctly in react-native?

I'm try to update the state from a function, but I don't find the correct form to bind the scope. My code (I am working with native-base components):
export default class MenuScreen extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
_renderRow() {
return (
<ListItem avatar onPress={() =>
ActionSheet.show(
{options: BUTTONS
}, buttonIndex => { setState({ clicked: BUTTONS[buttonIndex]})}
)}
>
</ListItem>
);
}
render() {
return (
<SectionList
sections={[...]}
renderItem={this._renderRow}
/>
);
}
First option, bind it in constructor
Example
constructor(props) {
super(props);
this.state = {};
this._renderRow = this._renderRow.bind(this);
}
Second option, bind it inline
Example
<SectionList
sections={[...]}
renderItem={this._renderRow.bind(this)}
/>
Third option, use arrow functions
Example
renderRow = () => {
return (
<ListItem avatar onPress={() =>
ActionSheet.show(
{options: BUTTONS
}, buttonIndex => { this.setState({ clicked: BUTTONS[buttonIndex]})}
)}
>
</ListItem>
);
}
My recommendation would be to read this:
https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56
Helps a lot with understanding binding options you have and why one or other might be better in your case.
I suggest to go with binding in constructor:
export default class MenuScreen extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleChange = this.handlePress.bind(this);
}
...
self mental note, "Bind is dummy if I not use the context of the function"
export default class MenuScreen extends React.Component {
constructor(props) {
super(props);
this.state = {};
**this._renderRow = this._renderRow.bind(this);**
}
_renderRow() {
return (
<ListItem avatar onPress={() =>
ActionSheet.show(
{options: BUTTONS
}, buttonIndex => { **this.**setState({ clicked: BUTTONS[buttonIndex]})}
)}
>
</ListItem>
);
}
render() {
return (
<SectionList
sections={[...]}
renderItem={this._renderRow}
/>
);
}

Categories

Resources