2

I have a list of tag objects in array (tagList), which I am fetching from the server and storing into the state. After a succesfull fetch I am mapping each item inside a ScrollView.

export default class RegisterTags extends Component {
    constructor(props) {
        super(props)
        this.state = {
            tagList: [],
            selectedTags: [],
        }
    }

    componentWillMount() {
        api.getTagsOnRegister()
            .then((res) => {
                this.setState({
                    tagList: res
                })
            })
    }

    insertTag = (tag) =>{
        this.setState({
            selectedTags: this.state.selectedTags.push(tag)
        })
    }


    render() {
        return(
            <View style={styles.container}>
                <ScrollView contentContainerStyle={styles.ScrollViewContainer}>
                    {this.state.tagList.map((tag) => {
                        return(
                            <View style={styles.tagStyle} key={tag.id} onPress={this.insertTag(tag)}>
                                <Text style={styles.tagText}>{tag.name}</Text>
                            </View>
                        )
                    })}
                </ScrollView>
            </View>
        )
    }
}

What I want to achieve is, when I press on any of the tag, I would like to add that object into the selectedTags array. But I am getting error:

Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

Possible Unhandled Promise Rejection (id: 0): _this.state.selectedTags.push is not a function TypeError: _this.state.selectedTags.push is not a function

How can I add the pressed tag item into the selectedTags array?

1 Answer 1

3
onPress={this.insertTag(tag)}

Issue: in your render function you are directly calling a function that changes state. Render function should never call any function that updates state.

So how to call onPress?

Ans: as written below

onPress = {() => {this.insertTag(tag) }}

Will code work now? Answer is no.

You have to put your views inside TouchableHighlight and move onPress method from View to TouchableHighlight. Then hopefully your code works. I am assuming everything is setup property.

~~~~~~EDIT 1~~~~~~~~

What't the difference between onPress={this.insertTag(tag)} and onPress = {() => {this.insertTag(tag) }}

Every thing inside curly braces are expressions in react jsx. Now onPress={this.insertTag(tag)} evaluates the expression inside curly braces and assign it to onPress property, and in your case this.insertTag happens to update state.

While onPress = {() => {this.insertTag(tag) }} , on evaluating curly braces returns a function, but doesn't call that function. And when onPress event is triggered than that function is called.

Google "Arrow Function" for more.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow.. I never realized this much. Its working, thank you sir. Could you please help me understand a little more on this concept. By calling a function like this onPress={this.insertTag(tag)} will automatically call the function on render, and calling a function like this onPress => {() = {this.insertTag(tag) }} will only call the function on press?
Hello, I have edited answer to explain arrow functions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.