Redux, как отфильтровать таски

Как отфильтровать таски, и при нажатии на кнопки DONE, ACTIVE, ALL показывать соответствующие им таски? Использую connect для передачи пропсов.

import React from 'react'
import shortid from 'shortid';

const ADD_TASK = 'ADD_TASK'
const EDIT_STATUS = 'EDIT_STATUS'
const TASK_DELETE = 'TASK_DELETE'

const SHOW_ALL = 'SHOW_ALL'
const SHOW_ACTIVE = 'SHOW_ACTIVE'
const SHOW_DONE = 'SHOW_DONE'


const initialState = {
    tasks: []
};


const mainReducer = (state = initialState, action) => {
    switch (action.type) {

        case ADD_TASK: {
            return {
                ...state,
                tasks: [{
                    id: shortid.generate(),
                    task: action.task,
                    status: false
                }, ...state.tasks]
            }
        }

        case EDIT_STATUS: {
            return {
                ...state,
                tasks: state.tasks.map(task => task.id === action.id ? {...task, status: !task.status} : task)
            }
        }

        case TASK_DELETE: {
            return {
                ...state,
                tasks: state.tasks.filter(t => t.id !== action.id)
            }
        }

        case SHOW_DONE: {
            return {

            }
        }

        case SHOW_ACTIVE: {
            return {

            }
        }


    default:
        return state
    }
}

export const showAll = () => ({type: 'SHOW_ALL'})
export const showActive = () => ({type: 'SHOW_ACTIVE'})
export const showDone = () => ({type: 'SHOW_DONE'})

export const addTask = task => ({type: 'ADD_TASK', task});
export const editStatus = id => ({type: 'EDIT_STATUS', id})
export const deleteTask = id => ({type: 'TASK_DELETE', id})


export default mainReducer;


import React from "react";
import s from "./../../App.module.css";
import Item from "./item"
import CurrentTasks from "../current-tasks";



class SetForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: ''
    }
  }

  onInputChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    })
  }

  handleSubmit = event => {
    event.preventDefault();
    if(this.state.text === '') {
      return undefined
    } 
    this.props.addTask(this.state.text)
    this.setState({
      text: ''
    })
  }


  render() {
    const filterTasks = (tasks, activeFilter) => {
      switch (activeFilter) {
        case 'done': {
          return tasks.filter(task => task.status);
        }
        case 'active': {
          return tasks.filter(task => !task.status)
        }
        default:
          return tasks;
      }
    };

    const currentTasks = filterTasks(this.props.tasks, this.props.filterReducer);


    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <div>
            <input
              name={"text"}
              onChange={this.onInputChange}
              value={this.state.text}
              placeholder={"Set your task"}
              className={s.setTask}
            />
            <button onClick={this.handleSubmit} className={s.add}>ADD</button>
          </div> 
        </form>
        <CurrentTasks tasks={this.props.tasks}/>
        {this.currentTasks}
        {this.props.tasks.map(t => (<Item editStatus={() => this.props.editStatus(t.id)}
                                          deleteTask={() => this.props.deleteTask(t.id)}
                                          key={t.id} task={t.task} status={t.status}/>))}
        {/* <FilterButtonTasks  tasks={this.props.tasks} /> */}
        <button onClick={() => this.props.changeFilter('all')}> all </button>
        <button onClick={() =>this.props.changeFilter('done')}> done</button>
        <button onClick={() =>this.props.changeFilter('active')}> active</button>
      </div>
    )
  }
}



export default SetForm;

import React from 'react'
import SetForm from './set-item'
import { compose } from 'redux'
import { addTask, editStatus, deleteTask,changeFilter} from '../../redux/main-reducer';
import { connect } from 'react-redux';




export class SetFormContainer extends React.Component {

    render(){
        return (
            <SetForm />
        )

    }
}


const mapStateToProps = (state) => {
    return {
        tasks: state.mainReducer.tasks,
        filter: state.filtersReducer
    }
}


export default compose(connect(mapStateToProps,{editStatus ,addTask,deleteTask,changeFilter}))(SetForm)


Ответы (1 шт):

Автор решения: 1ocke

Файл с редьюсерами.

import React from 'react';
import { combineReducers } from 'redux';
import shortid from 'shortid';

const ADD_TASK = 'ADD_TASK';
const EDIT_STATUS = 'EDIT_STATUS';
const TASK_DELETE = 'TASK_DELETE';
const CHANGE_FILTER = 'CHANGE_FILTER';

const baseFilter = 'all';
const initialState = {
    tasks: []
};


const tasksReducer = (state = initialState, action) => {
    switch (action.type) {

        case ADD_TASK: {
            return {
                ...state,
                tasks: [{
                    id: shortid.generate(),
                    task: action.task,
                    status: false
                }, ...state.tasks]
            }
        }

        case EDIT_STATUS: {
            return {
                ...state,
                tasks: state.tasks.map(task => task.id === action.id ? {...task, status: !task.status} : task)
            }
        }

        case TASK_DELETE: {
            return {
                ...state,
                tasks: state.tasks.filter(t => t.id !== action.id)
            }
        }

    default:
        return state
    }
}

const filtersReducer = (state = baseFilter, action) => {
  switch (action.type) {
    case CHANGE_FILTER: {
      return action.activeFilter;
    }
    default:
      return state;
  }
}

export const addTask = task => ({type: 'ADD_TASK', task});
export const editStatus = id => ({type: 'EDIT_STATUS', id})
export const deleteTask = id => ({type: 'TASK_DELETE', id})
export const changeFilter = activeFilter => ({type: CHANGE_FILTER, activeFilter})

const mainReducer = combineReducers({tasksReducer, filtersReducer})
export default mainReducer;

После в нашем компоненте вытаскиваем из пропсов filtersReducer, где хранится название нашего фильтра (по-умолчанию 'all'). И экшен changeFilter, который вешаем на кнопки с соответсвующим аргументом.

А также создаем в компоненте функцию фильтрации тасков, куда передаем таски и наш filtersReducer.

Файл с компонентом.

import React from "react";
import s from "./../../App.module.css";
import Item from "./item"
import CurrentTasks from "../current-tasks";

class SetForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: ''
    }
  }

  onInputChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    })
  }

  handleSubmit = event => {
    event.preventDefault();
    if(this.state.text === '') {
      return undefined
    } 
    this.props.addTask(this.state.text)
    this.setState({
      text: ''
    })
  }

  filterTasks = (tasks, activeFilter) => {
    switch (activeFilter) {
      case 'done': {
        return tasks.filter(task => task.status);
      }
      case 'active': {
        return tasks.filter(task => !task.status)
      }
      default:
        return tasks;
    }
  }


  render() {
    const currentTasks = this.filterTasks(this.props.tasks, this.props.filter);


    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <div>
            <input
              name={"text"}
              onChange={this.onInputChange}
              value={this.state.text}
              placeholder={"Set your task"}
              className={s.setTask}
            />
            <button onClick={this.handleSubmit} className={s.add}>ADD</button>
          </div> 
        </form>
        <CurrentTasks tasks={this.props.tasks}/>
        {currentTasks.map(t => (<Item editStatus={() => this.props.editStatus(t.id)}
                                          deleteTask={() => this.props.deleteTask(t.id)}
                                          key={t.id} task={t.task} status={t.status}/>))}
        {/* <FilterButtonTasks  tasks={this.props.tasks} /> */}
        <button onClick={() => this.props.changeFilter('all')}> all </button>
        <button onClick={() =>this.props.changeFilter('done')}> done</button>
        <button onClick={() =>this.props.changeFilter('active')}> active</button>
      </div>
    )
  }
}



export default SetForm;
→ Ссылка