0

I want to have options where if a user chooses 'all' it should display the whole array, if 'active' then only items in array that are not checked, and 'complete' for all checked values.

But, I don't get the whole array when switching between options. For example, if I choose 'active', then 'complete' and then 'all', at the end nothing will show because after switching array is empty.

I tried to copy existing array in temporary state and then manipulate with it, but not working.

This is how it looks like:

const [todo, dispatch] = useReducer((state: any, action: any): any => {
    switch (action.type) {
        //...
        case 'SELECT':
            switch (action.option) {
                case 'all':
                    const temp1 = [...state]
                    return temp1
                case 'complete':
                    const temp2 = [...state]
                    return temp2.filter((i: any) => i.isCheck === true)
                case 'active':
                    const temp3 = [...state]
                    return temp3.filter((i: any) => i.isCheck === false)
                default:
                    return state
            }
    }
}, [])
<select onChange={(e: any) => dispatch({ type: 'SELECT', option: e.target.value })}>
    <option value="choose" selected>Choose</option>
    <option value="all">All</option>
    <option value="active">Active</option>
    <option value="complete">Complete</option>
</select>

And here is whole component : https://pastebin.com/Xr1gm4dV

Any solutions or ideas?

EDIT:

const [options, setOptions] = useState([{}])

const [todo, dispatch] = useReducer((state: any, action: any): any => {

    setOptions([...state])

    switch (action.type) {
        //...
        case 'SELECT':
            switch (action.option) {
                case 'all':
                    setOptions([...state])
                    return options
                case 'complete':
                    setOptions([...state])
                    return options.filter((i: any) => i.isCheck === true)
                case 'active':
                    setOptions([...state])
                    return options.filter((i: any) => i.isCheck === false)
                default:
                    return state
            }
    }
})
2
  • You are modifying your original array therefore whenever you are filtering array, fitered values are lost forever. Instead try to store 'all', 'active' and 'complete' in your state and filter todo appropriately while rendering. Commented Apr 25, 2020 at 10:46
  • Ok, I did something, now only "all" doesn't work like it suppose to. Can you check my EDIT? Commented Apr 25, 2020 at 11:05

1 Answer 1

1

Store your original array in another state. Now you can render using todo array. OriginalArray never gets lost.

const [originalArray, setOriginalArray] = useState([])

const [todo, dispatch] = useReducer((state: any, action: any): any => {
    switch (action.type) {
        //...
        case 'SELECT':
            switch (action.option) {
                case 'all':
                    return originalArray
                case 'complete':
                    return originalArray.filter((i: any) => i.isCheck === true)
                case 'active':
                    return originalArray.filter((i: any) => i.isCheck === false)
                default:
                    return state
            }
    }
})

Edit (posting working code here)

import React, { useRef, useReducer, useState } from 'react'

export default function App() {

    const inputRef = useRef<HTMLInputElement | any>(null)

    const handleSubmit = (e: any) => {
        e.preventDefault()
        if (inputRef.current?.value !== "") {
            dispatch({
                type: 'ADD_TODO',
                payload: inputRef.current?.value,
                id: editingIndex
            })
        }
        inputRef.current && (inputRef.current.value = "")
    }

    const [editingIndex, setEditingIndex] = useState<null | number>(null)
    const [selected, setSelected] = useState<'all' | 'active' | 'selected'>('all')

    const [todo, dispatch] = useReducer((state: any, action: any): any => {
        
        switch (action.type) {
            case 'ADD_TODO':
                setEditingIndex(null)
                const tempState = [...state]
                if (action.id) {
                    tempState[action.id] = { ...tempState[action.id], name: action.payload }
                }
                else {
                    tempState.push({
                        id: action.id | state.length,
                        name: action.payload,
                        isCheck: false,
                        toggleAll: false
                    })
                }
                return tempState
            case 'CHECK_TODO':
                return state.filter((item: any, index: any): any => {
                    if (index === action.id) {
                        item.isCheck = !item.isCheck
                    }
                    return item
                })
            case 'EDIT_TODO':
                inputRef.current.focus()
                inputRef.current.value = action.payload
                return state
            case 'DELETE_TODO':
                return state.filter((item: any, index: any) => index !== action.id)
            case 'CLEAR_TODOS':
                return []
            case 'ON_OFF':
                const newState = state.map((item: any) => {
                    item.toggleAll = !item.toggleAll
                    return item
                })
                return newState.map((item: any) => {
                    item.isCheck = item.toggleAll
                    return item
                })
            default: 
                return state 
        }
    }, [])

    const handleEditing = (index: number, item: { name: string }) => {
        setEditingIndex(index);
        dispatch({
            type: 'EDIT_TODO',
            id: index,
            payload: item.name
        })
    }

    const todos = todo.map((item: any, index: number) => {
        if(selected === 'active' && item.isCheck) return null
        if(selected === 'complete' && !item.isCheck) return null
        return (
            <li key={index}>
                <input
                    type="checkbox"
                    checked={item.isCheck}
                    onChange={() => dispatch({ type: 'CHECK_TODO', id: index })}
                />
                {item.name}
                <button onClick={() => handleEditing(index, item)}>/</button>
                <button onClick={() => dispatch({ type: 'DELETE_TODO', id: index })}>x</button>
            </li>
        )
    })

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    placeholder='Buy milk'
                    ref={inputRef}
                />
            </form>
            <button onClick={() => dispatch({ type: 'CLEAR_TODOS' })}>Clear</button>
            <button onClick={() => dispatch({ type: 'ON_OFF' })}>On/Off</button>

            <select value={selected} onChange={(e: any) => setSelected(e.target.value)}>
                <option value="choose" selected>Choose</option>
                <option value="all">All</option>
                <option value="active">Active</option>
                <option value="complete">Complete</option>
            </select>
            <ul>{todos}</ul>
        </div>
    )
}

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

15 Comments

Aha, I did something like that, can you see my EDIT? I tried that and only option 'all' doesn't work like it suppose to, why is that so? EDIT: And I modified code like you did, still not working like it suppose to
I saw your code. You are still modifying originalArray. Can you please host a sandbox. That will be easier to work with.
I'm sorry, I additionally added package.json in there, it is displaying everything now, can you check it again? I open what you did but still same problem.
|

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.