I've tried to console.log the value of the text input but I get the error "undefined is not an object (evaluating 'this.state.inputValue')". What's the problem? Thank you!
class SearchScreen extends React.Component {
state = {
inputValue: "",
};
search() {
console.log(this.state.inputValue);
}
render() {
return (
<View>
<TextInput
onChangeText={
((inputValue) => this.setState({ inputValue }),
this.search)
}
value={this.state.inputValue}
/>
</View>
);
}
}
export default SearchScreen;
The problem is in the way you've implemented it. Please try as below...
class SearchScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: '',
};
}
search() {
console.log(this.state.inputValue);
}
render() {
return (
<View>
<TextInput
onChangeText={(inputValue) => {
this.setState({ inputValue });
this.search();
}}
value={this.state.inputValue}
/>
</View>
);
}
}
export default SearchScreen;
This problem occurred because two things.
First:
The this.setState is a async function.
If you pass a function after the setState this will work like a .then() in a promisse.
Second:
If you pass one function after another separating them by ',' the rightmost function will be executed first
You can resolve this doing something like that:
onChange={ inputValue => {
this.setState({ inputValue });
this.search();
}}
Or you can try something like that:
class SearchScreen extends React.Component {
state = {
inputValue: "",
};
search = () {
console.log(this.state.inputValue);
}
setSearch = inputValue => {
// The function 'search' will be execute after the state was set
this.setState(
{ inputValue },
() => this.search()
);
}
render() {
return (
<View>
<TextInput
onChangeText={ inputValue => this.setSearch(inputValue) }
value={this.state.inputValue}
/>
</View>
);
}
}
export default SearchScreen;
You didn't set the value of state property. provide a value to setState.
this.setState({property : value})
The problem is this line:
onChangeText={
((inputValue) => this.setState({ inputValue }),
this.search)
}
You can use the short function notation only when your function has one statement:
(inputValue) => this.setState({ inputValue })
You actualy have 2 statements though, so you need to create a full function block using {}
(inputValue) => {
this.setState({ inputValue })
this.search()
}
Related
I've created a class based component that renders an input field. I need the global state to update while the user types into the input. The issue is that the global state is always one step (render?) behind from what's actually in the input field. For example, when I write “winners” in the input, the state is “winner” instead. How can I fix this?
Component
class TeamCardT1 extends Component {
constructor(props) {
super(props);
// local state
this.state = {
team_one_name: "Team One",
};
// bind events
this.handleName = this.handleName.bind(this);
};
handleName = e => {
this.setState({
...this.state,
team_one_name: e.target.value
});
this.props.handleSubmit(this.state);
};
render() {
const { team_one_name } = this.state;
return (
<>
<div className="teamCard_container">
<input
type="text"
id="team_one_name"
name="team_one_name"
value={team_one_name}
onChange={this.handleName}
maxLength="35"
minLength="2"
className="teamCard_teamName" />
<PlayersCardT1 />
<ScoreCard />
</div>
</>
)
};
}
index.js for the component
const mapStateToProps = ({ team_one_name }) => {
return {
team_one_name,
};
};
// Dispatch
const mapDispatchToProps = dispatch => {
return {
handleSubmit: (data) => { dispatch(updateTeamOneName(data)) }
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TeamCardT1);
You handleSubmit with the previous state, change to the current value.
handleName = e => {
this.setState({ team_one_name: e.target.value });
this.props.handleSubmit(e.target.value);
};
Notice that you already have a shallow merge with setState so you don't need to destruct this.state.
state is one step behind because you should call the prop function as a setState callback by this way the prop function will call just after the state set.
handleName = e => {
this.setState({
...this.state,
team_one_name: e.target.value
}, () => {
this.props.handleSubmit({value: e.target.value});
});
};
I am Trying to Create a React App That Detects Age of Pictures Using Clarifai API .
I am Able to Console.Log Detected Age but I Want To Display The Age on My Webpage . Help me With Setting The AgeDectect State so I Can Use it on my Webpage
//Value Displayed On Console
//39
//App.js Code That Console.Logs Age
class App extends Component {
constructor(){
super();
this.state = {
input : '',
imgURL : '',
AgeDetect : ''
}
}
onInputChange = (event) => {
this.setState({input : event.target.value});
}
onClickEvent = () => {
this.setState({imgURL : this.state.input})
app.models.predict(Clarifai.DEMOGRAPHICS_MODEL ,
this.state.input).then(
function(response) {
const A =response.outputs[0].data.regions[0].
data.face.age_appearance.concepts[0].name
//This Line of Code Displays Age on Console
console.log(A);
this.setState({AgeDetect : A});
},
//Having Problem SettingState ,this.state.AgeDetect isnt
//doing anything
render(){
return (<AgeDetection AgeDetect={this.state.AgeDetect}/>
)
}
//AgeDetection.js file
import React from 'react' ;
const AgeDetection = ({AgeDetect}) => {
return(
<div>
{AgeDetect}
</div>
);
}
export default AgeDetection;
Sort your array that is returned by the value and set the first object or the whole array to your state and then you can use it in your app very easily. Use an arrow function inside your predict then block to bind to the class.
class App extends Component {
constructor() {
super();
this.state = {
input: '',
imgURL: '',
AgeDetect: ''
};
}
onInputChange = event => {
this.setState({ input: event.target.value });
};
onClickEvent = () => {
this.setState({ imgURL: this.state.input });
app.models.predict(Clarifai.DEMOGRAPHICS_MODEL, this.state.input).then(
response => {
const A =
response.outputs[0].data.regions[0].data.face.age_appearance
.concepts[0].name;
this.setState({ AgeDetect: A });
},
function(err) {
// there was an error
}
);
};
render() {
console.log(this.state);
return (
<div className='App'>
<Navigation />
<Logo />
<ImageLinkForm
onInputChange={this.onInputChange}
onClickEvent={this.onClickEvent}
/>
<FaceRecognition imgURL={this.state.imgURL} />
<AgeDetection AgeDetect={this.state.AgeDetect} />
</div>
);
}
}
export default App;
I have a component where when I click on an icon, I execute a function that modify a state and then i can check the state and modify the icon. In that comonent, I am mapping datas and it renders several items.
But when I click on one icon all the icons of the components change too.
Here is the code for the component
export default class DiscoveryComponent extends Component {
constructor(props) {
super(props)
this.state = {
starSelected: false
};
}
static propTypes = {
discoveries: PropTypes.array.isRequired
};
onPressStar() {
this.setState({ starSelected: !this.state.starSelected })
}
render() {
return (
this.props.discoveries.map((discovery, index) => {
return (
<Card key={index} style={{flex: 0}}>
<CardItem>
<TouchableOpacity style={[styles.star]}>
<Icon style={[styles.iconStar]} name={(this.state.starSelected == true)?'star':'star-outline'} onPress={this.onPressStar.bind(this)}/>
</TouchableOpacity>
</CardItem>
</Card>
)
})
);
}
}
And here is the code for my screen that uses the component
export default class DiscoveryItem extends Component {
constructor(props) {
super(props);
this.state = {
discoveries: [],
loading: true
};
}
componentDidMount() {
firebase.database().ref("discoveries/").on('value', (snapshot) => {
let data = snapshot.val();
let discoveries = Object.values(data);
this.setState({discoveries: discoveries, loading: false});
});
}
render() {
return (
<Container>
<Content>
<DiscoveryComponent discoveries={this.state.discoveries} />
</Content>
</Container>
)
}
}
Your initiation is correct but you are missing INDEX of each item. Inside this.onPressStar() method check if item's index = currentItem. Also don't forget to set item id = index onpress.
I hope this has given you idea how to handle it.
You have to turn your stars into an Array and index them:
change your constructor:
constructor(props) {
super(props)
this.state = {
starSelected: []
};
}
change your onPressStar function to :
onPressStar(index) {
this.setState({ starSelected[index]: !this.state.starSelected })
}
and your icon to
<Icon style={[styles.iconStar]} name={(this.state.starSelected[index] == true)?'star':'star-outline'} onPress={()=>this.onPressStar(index)}/>
Well, the problem is that you have a single 'starSelected' value that all of your rendered items in your map function are listening to. So when it becomes true for one, it becomes true for all.
You should probably maintain selected state in the top level component, and pass down the discovery, whether its selected, and how to toggle being selected as props to a render function for each discovery.
export default class DiscoveryItem extends Component {
constructor(props) {
super(props);
this.state = {
discoveries: [],
selectedDiscoveries: [] // NEW
loading: true
};
}
toggleDiscovery = (discoveryId) => {
this.setState(prevState => {
const {selectedDiscoveries} = prevstate
const discoveryIndex = selectedDiscoveries.findIndex(id => id === discoveryId)
if (discoveryIndex === -1) { //not found
selectedDiscoveries.push(discoveryId) // add id to selected list
} else {
selectedDiscoveries.splice(discoveryIndex, 1) // remove from selected list
}
return {selectedDiscoveries}
}
}
componentDidMount() {
firebase.database().ref("discoveries/").on('value', (snapshot) => {
let data = snapshot.val();
let discoveries = Object.values(data);
this.setState({discoveries: discoveries, loading: false});
});
}
render() {
return (
<Container>
<Content>
{
this.state.discoveries.map(d => {
return <DiscoveryComponent key={d.id} discovery={d} selected={selectedDiscoveries.includes(d.id)} toggleSelected={this.toggleDiscovery} />
//<DiscoveryComponent discoveries={this.state.discoveries} />
</Content>
</Container>
)
}
}
You can then use your DiscoveryComponent to render for each one, and you're now maintaining state at the top level, and passing down the discovery, if it is selected, and the toggle function as props.
Also, I think you may be able to get snapshot.docs() from firebase (I'm not sure as I use firestore) which then makes sure that the document Id is included in the value. If snapshot.val() doesn't include the id, then you should figure out how to include that to make sure that you use the id as both key in the map function as well as for the selectedDiscoveries array.
Hope that helps
It works now, thanks.
I've made a mix between Malik and Rodrigo's answer.
Here is the code of my component now
export default class DiscoveryComponent extends Component {
constructor(props) {
super(props)
this.state = {
tabStarSelected: []
};
}
static propTypes = {
discoveries: PropTypes.array.isRequired
};
onPressStar(index) {
let tab = this.state.tabStarSelected;
if (tabStar.includes(index)) {
tabStar.splice( tabStar.indexOf(index), 1 );
}
else {
tabStar.push(index);
}
this.setState({ tabStarSelected: tab })
}
render() {
return (
this.props.discoveries.map((discovery, index) => {
return (
<Card key={index} style={{flex: 0}}>
<CardItem>
<Left>
<Body>
<Text note>{discovery.category}</Text>
<Text style={[styles.title]}>{discovery.title}</Text>
</Body>
</Left>
<TouchableOpacity style={[styles.star]}>
<Icon style={[styles.iconStar]} name={(this.state.tabStarSelected[index] == index)?'star':'star-outline'} onPress={()=>this.onPressStar(index)}/>
</TouchableOpacity>
</CardItem>
</Card>
)
})
);
}
}
I've been using React native for a month now but it's my first time to use a CheckBox in my application. So, lately I've been struggling to check a specific checkbox inside a Flatlist but now I can.
But upon testing my checkboxs I did notice that once I check a specific a CheckBox(or more than 1 checkbox) it doesn't UNCHECK.
So, my goal is to make a CheckBox that can check(ofcourse) and also uncheck, if ever a user mischeck or mistap a CheckBox.
Here's my code
export default class tables extends Component {
constructor(props){
super(props)
this.state = {
...
check: false
}
}
checkBox_Test = (item, index) => {
let { check } = this.state;
check[index] = !check[index];
this.setState({ check: check })
alert("now the value is " + !this.state.check);
alert("now the value is " + item.tbl_id);
console.log(item.tbl_id)
}
render() {
return(
<View>
....
<Flatlist
....
<CheckBox
value = { this.state.check }
onChange = {() => this.checkBox_Test(item) }
/>
....
/>
<View/>
)
}
}
Method 1: Make check an object
export default class tables extends Component {
constructor(props){
super(props)
this.state = {
...
check: {}
}
}
checkBox_Test = (id) => {
const checkCopy = {...this.state.check}
if (checkCopy[id]) checkCopy[id] = false;
else checkCopy[id] = true;
this.setState({ check: checkCopy });
}
render() {
return(
<View>
....
<Flatlist
....
<CheckBox
value = { this.state.check[item.tbl_id] }
onChange = {() => this.checkBox_Test(item.tbl_id) }
/>
....
/>
<View/>
)
}
}
Method 2: Make a separate item for each FlatList item
class ListItem extends Component {
constructor(props){
super(props)
this.state = {
...
check: false
}
}
checkBox_Test = (id) => {
this.setState((prevState) => ({ check: !prevState.check }));
}
render() {
return(
<View>
<CheckBox
value = { this.state.check }
onChange = { this.checkBox_Test }
/>
</View>
)
}
}
Let me know if it works for you
I'm starting with react native and trying to bind some actions to class methods but I'm getting some errors about methods not found.
I tried binding:
class AccountsScreen extends Component {
constructor (props) {
super(props)
this.userChange = this.userChange.bind(this)
this.state = {
user: '',
password: ''
}
}
render () {
return (
<View>
<Text>Pass</Text>
<TextInput
onChange={this.userChange}
/>
</View>
)
}
userChange (user) {
this.setState({user: user})
}
}
and arrow functions
class AccountsScreen extends Component {
constructor (props) {
super(props)
this.state = {
user: '',
password: ''
}
}
render () {
return (
<View>
<Text>Pass</Text>
<TextInput
onChange={(user) => this.userChange(user)}
/>
</View>
)
}
userChange (user) {
this.setState({user: user})
}
}
but I keep getting the same error:
"this.setState is not a function"
Totally stuck. Any ideas?
actually no need to make a function to set your state, you can just do this
<TextInput onChangeText={(user) => this.setState({user: user})} />
Actually it was a stupid mistake. I was using onChange instead of onChangeText method....