3

I'm making simple Todo Application using React Native + Redux following Youtube.

Adding Todo works well. so I took next step, trying to deleting todo got problem. The Video is little bit old, so the version and platform(Mine is Android) is different. so the way of it little different... (ES5/ES6 etc.)

Anyway... I want to send action to dispatcher using mapDispatchToProps's function, onDeleteTodo, but it's not working.

First I tried to connect the component to store, so Added line TodoItem = connect(mapStateToProps, mapDispatchToProps)(TodoItem);. but the error still left.

Something wrong... but I can't find, How can I fix it?

Thanks in advance... below is my code.

import React, {Component} from 'react';
import {
    StyleSheet,
    Text,
    View,
    TextInput,
    ScrollView,
    TouchableOpacity
} from 'react-native';

import {connect} from 'react-redux';
import {addTodo, deleteTodo} from '../actions';

class TodoItem extends Component {
    render() {
        return (

// ***************************************
// Below line (onPress prop) is problem. 
// when I trying to save todo, 
// Error "undefined is not a function (evaluating 'this.props.onDeleteTodo(this.props.id)')

            <TouchableOpacity onPress={this.props.onDeleteTodo(this.props.id)}>
                <View style={styles.todoContainer}>
                    <Text style={styles.todoText}>
                        {this.props.text}
                    </Text>
                </View>
            </TouchableOpacity>
        )
    }
}

TodoItem = connect(
    mapStateToProps,
    mapDispatchToProps
)(TodoItem);


class Main extends Component {
    constructor(props) {
        super(props);
        this.state = {
            newTodoText: ""
        }
    }


    render() {
        var renderTodos = () => {
            return this.props.todos.map((todo) => {
                return (
                    <TodoItem text={todo.text} key={todo.id} id={todo.id}/>
                )
            })
        };

        return (
            <View style={styles.wrapper}>
                <View style={styles.topBar}>
                    <Text style={styles.title}>
                        To-Do List
                    </Text>
                </View>
                <View style={styles.inputWrapper}>
                    <TextInput
                        onChange={(event) => {
                            this.setState({
                                 newTodoText: event.nativeEvent.text
                            });
                        }}
                        value={this.state.newTodoText}
                        returnKeyType="done"
                        placeholder="New Todo"
                        onSubmitEditing={
                        () => {
                            if(this.state.newTodoText && this.state.newTodoText != ''){
                                  this.props.onAddTodo(this.state.newTodoText);
                                this.setState({
                                     newTodoText: ''
                                });
                            }

                        }
                        }
                        underlineColorAndroid='transparent'
                        style={styles.input}/>
                </View>
                <ScrollView
                    automaticallyAdjustContentInsets={false}>
                    {renderTodos()}
                </ScrollView>

            </View>
        );
    }
}

const mapStateToProps = (state) => {
    return {
        todos: state.todos
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        onAddTodo: (todo) => {
            dispatch(addTodo(todo))
        },
        onDeleteTodo: (id) => {
            dispatch(deleteTodo(id))
        }
    }
};

Main = connect(
    mapStateToProps,
    mapDispatchToProps
)(Main);

export default Main
ton1
  • 7,238
  • 18
  • 71
  • 126

3 Answers3

1

If you write yoru code like this onPress={ this.props.onDeleteTodo(this.props.id) } then you are passing to the onPress property anything that is returned by the function this.props.onDeleteTodo. In other words, this.props.onDeleteTodo is executed when the component is rendering.

If you want to pass this function (and not it's returned value) then you need to write onPress={ this.props.onDeleteTodo.bind(this, this.props.id) }. This way you are passing this function with this as a context and this.props.id as it's first argument. More about this method here: Use of the JavaScript 'bind' method

Community
  • 1
  • 1
Deividas
  • 6,437
  • 2
  • 26
  • 27
0

I don't really know If I've understood your code... By the way, if you are importing any function from somewhere, I think that you don't have to use dispatch method, since deleteTodo is not a property method. Try again without dispatch(), moreover, try to call directly deleteTodo() method.

EDIT: in onPress event write this -> onPress={() => deleteTodo(this.props.id)} It should call the method onces the event is triggered

And let me know if it works!

  • But **Redux** seems to compelling use that way... I think it want to indirectly use dispatch functions... – ton1 Mar 01 '17 at 11:12
  • The code that you have added is in the same file? If it is, you should have the two classes in separate files just for clear code... Furthermore, I would define some Prototypes, like this: TodoItem.Proptype = { onDeleteTodo = React.Proptype.func, } With this, I'll make sure that the functions exists, and then, in mapDispatchToProps, define it... – Borja Navarro Mar 01 '17 at 11:16
0

I found the solution... but I don't know why it works.

  1. change prop to callback function

    onPress={this.props.onDeleteTodo(this.props.id)}

    ==>

    onPress={ () => { this.props.onDeleteTodo(this.props.id) } }

: Is onPress prop only receive callback function? I don't know.

  1. Move connect statement to below of const mapStateToProps and mapDispatchToProps

: Is const ... variable only can reference below its declaration? I don't know also.

ton1
  • 7,238
  • 18
  • 71
  • 126