简体   繁体   中英

React Native (Redux) dispatch action (in parent component) from const in different file

FOUND ANSWER, ACCESSING WHOLE STATE INSTEAD OF TODO, answer below.

I have a bound function in a component which I pass to a const. The checkbox clicks correctly once but then it stops working. What am I doing wrong?

The toggleTodoOnPress is called correctly once but then stops responding. The value changes from false to true correctly but then gets stuck on true when checkbox is clicked again. The checkbox value shows false even though todo.complete is true. After one click the function is never called again.

Parent Compenent:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {
  View,
  Text,
  TouchableOpacity,
  ScrollView,
  TextInput,
  StyleSheet,
  Dimensions,
} from 'react-native';
import {addTodo, toggleTodo} from './action/Todo';
import Todo from './component/Todo';
import {addTextInputPlaceholderText, addTodoButtonText} from './Constants';

let ScreenHeight = Dimensions.get('window').height;
let addTodoBarHeight = 0.08 * ScreenHeight;

class TodoApp extends Component {
  constructor(props) {
    super(props);
    this.toggleTodoOnPress = this.toggleTodoOnPress.bind(this);
  }

  state = {
    todo: '',
    todos: [],
  };

  addTodoInputOnChangeText = (value) => {
    this.setState({
      todo: value,
    });
  };

  addTodoOnPress = () => {
    if (this.state.todo.trim() === '') {
      return;
    }
    this.props.addTodo(this.state.todo);
    this.setState({
      todo: '',
    });
  };

  toggleTodoOnPress = (id) => {
    this.props.toggleTodo(id);
  };

  render() {
    console.log(this.props.todos)
    var todosList = this.props.todos;
    var todos = [];
    for (let i = 0; i < todosList.length; i++) {
      todos.push(
        <Todo
          key={'todo-' + todosList[i].id}
          todo={todosList[i]}
          toggleTodoOnPress={(id) => this.toggleTodoOnPress(todosList[i].id)}
        />,
      );
    }
    return (
      <View>
        <View style={styles.inputContainer}>
          <TextInput
            placeholder={addTextInputPlaceholderText}
            placeholderTextColor="white"
            style={styles.addTextInput}
            value={this.state.todo}
            onChangeText={this.addTodoInputOnChangeText}
          />
          <TouchableOpacity
            style={styles.addButton}
            onPress={this.addTodoOnPress}
            title={addTodoButtonText}>
            <Text style={styles.addButtonText}>{addTodoButtonText}</Text>
          </TouchableOpacity>
        </View>
        <ScrollView>{todos}</ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  inputContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    height: addTodoBarHeight,
    width: '100%',
  },
  addTextInput: {
    paddingLeft: 16,
    fontSize: 16,
    height: '100%',
    width: '70%',
    backgroundColor: 'black',
    color: 'white',
  },
  addButton: {
    alignItems: 'center',
    justifyContent: 'center',
    height: '100%',
    width: '30%',
    backgroundColor: 'green',
  },
  addButtonText: {
    fontSize: 18,
    color: 'white',
  },
});

const mapStateToProps = (state) => {
  return {
    todos: state.Todos.todos.length === 0 ? [] : state.Todos.todos,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    addTodo: (task) => {
      dispatch(addTodo(task));
    },
    toggleTodo: (id) => {
      dispatch(toggleTodo(id));
    },
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);

Child Const:

import React from 'react';
import {connect} from 'react-redux';
import {View, Text, StyleSheet} from 'react-native';
import CheckBox from '@react-native-community/checkbox';

const Todo = ({todo, toggleTodoOnPress}) => (
  console.log(todo.complete),
  <View style={styles.todoContainer}>
    <Text style={styles.todoText}>{todo.content}</Text>
    <View style={styles.todoCheckboxContainer}>
      <CheckBox
        value={todo.complete}
        onChange={toggleTodoOnPress}
        onValueChange={toggleTodoOnPress}
        tintColors={{true: 'green', false: 'black'}}
        tintColor='black'
        onCheckColor='white'
        onFillColor='green'
        onTintColor='green'
      />
    </View>
  </View>
);

const styles = StyleSheet.create({
  todoContainer: {
    backgroundColor: 'white',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    width: '100%',
  },
  todoText: {
    fontWeight: 'bold',
    fontSize: 18,
    padding: 12,
    paddingTop: 16,
    paddingBottom: 16,
    width: '90%',
  },
  todoCheckboxContainer: {
    alignItems: 'center',
    justifyContent: 'center',
    width: '10%',
  },
});

export default Todo;

toggleTodo reducer:

const Todos = (state = initialState, action) => {
  switch (action.type) {
    case TODO_ADD:
      return {
        ...state,
        todos: state.todos.concat({
          id: action.id,
          content: action.content,
          complete: action.complete,
        }),
      };
    case TODO_TOGGLE:
      return {
        ...state,
        todos: state.todos.map((todo) =>
          todo.id === action.id
            ? {
                ...todo,
                complete: !state.complete,
              }
            : todo,
        ),
      };
    default:
      return state;
  }
};

Hope the question makes sense, happy to explain.

Error was in toggleTodo reducer, changed...state to...todo, was accessing entire state instead of the single todo.

toggleTodo reducer updated (correct):

const Todos = (state = initialState, action) => {
  switch (action.type) {
    case TODO_ADD:
      return {
        ...state,
        todos: state.todos.concat({
          id: action.id,
          content: action.content,
          complete: action.complete,
        }),
      };
    case TODO_TOGGLE:
      return {
        ...state,
        todos: state.todos.map((todo) =>
          todo.id === action.id
            ? {
                ...todo,
                complete: !todo.complete,
              }
            : todo,
        ),
      };
    default:
      return state;
  }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM