'Component shows old state after action happened
After action is happened component gets an old state anyway. I'm not mutating the state btw. The changes appears only after I refresh the page
My component TodoList.tsx
Here's I'm trying to get state via useEffect hook
export const TodoList: FC = () => {
const {
todoList, isLoading, isError, message
} = useTypedSelector(
(state) => state.todo
)
console.log(todoList)
const { getTodo, reset } = useActions()
useEffect(() => {
getTodo()
console.log("render")
if (isError) {
console.log(message)
}
return () => {
reset()
}
}, [])
const statusHandler = (event: React.ChangeEvent<HTMLParagraphElement>) => {
const status = event.target.innerText
if (status === "completed") {
getTodo({ complete: true })
} else if (status === "uncompleted") {
getTodo({ complete: false })
} else if (status === "all") {
getTodo()
}
}
return (
<>
...
</>
)
}
my Reducer
I'm not mutating the state also.
const initialState: TodoState = {
todoList: [],
isError: false,
isSuccess: false,
isLoading: false,
message: ""
}
export const todoReducer = (state = initialState, { type, payload }: TodoAction): TodoState => {
switch (type) {
case "GET_TODOS":
return { ...state, isLoading: true }
case "GET_TODOS_SUCCESS":
return { ...state, isLoading: false, isSuccess: true, todoList: payload }
case "GET_TODOS_ERROR":
return { ...state, isLoading: false, isError: true, message: payload.error }
case "CREATE_TODO":
return { ...state, isLoading: false }
case "CREATE_TODO_SUCCESS":
return { ...state, isLoading: false, isSuccess: true, todoList: [...state.todoList, payload]}
case "CREATE_TODO_ERROR":
return { ...state, isLoading: false, isError: true, message: payload.error }
case "TOGGLE_TODO":
return { ...state, isLoading: true }
case "TOGGLE_TODO_SUCCESS":
return {
...state, isLoading: false, isSuccess: true, todoList: state.todoList.map((todo: ITodoItem) => {
if (todo._id === payload.id) {
console.log(payload)
return {
...todo,
complete: !todo.complete
}
}
return todo
})
}
case "TOGGLE_TODO_ERROR":
return { ...state, isLoading: false, isError: true, message: payload.error }
case "DELETE_TODO":
return { ...state, isLoading: true }
case "DELETE_TODO_SUCCESS":
return {
...state, isLoading: false, isSuccess: true, todoList: state.todoList.filter(
(todo: ITodoItem) => todo._id !== payload.id
)
}
case "DELETE_TODO_ERROR":
return { ...state, isLoading: false, isError: true, message: payload.error }
case "EDIT_TODO":
return { ...state, isLoading: true }
case "EDIT_TODO_SUCCESS":
return {
...state, isLoading: false, isSuccess: true, todoList: state.todoList.map((todo: ITodoItem) => {
if (todo._id === payload.id) {
return {
...todo,
text: payload.text
}
}
return todo
})
}
case "EDIT_TODO_ERROR":
return { ...state, isLoading: false, isError: true, message: payload.error }
case "RESET_TODOS":
return { ...state, todoList: state.todoList }
default:
return state
}
}
my action creator
Here I'm making a request from my own api.
...
export const getTodo = (data?: GetTodos) => {
return async (dispatch: Dispatch<TodoAction>): Promise<void> => {
try {
dispatch({ type: "GET_TODOS", payload: {} })
let response
if (data) {
response = await todoService.getTodo((<any>data).complete)
}
response = await todoService.getTodo()
console.log(response)
dispatch({ type: "GET_TODOS_SUCCESS", payload: response })
} catch (err) {
dispatch({
type: "GET_TODOS_ERROR",
payload: { error: "Cannot fetch the todos. Please try again later" }
})
}
}
}
export const createTodo = (payload: CreateTodo) => {
return async (dispatch: Dispatch<TodoAction>): Promise<void> => {
try {
dispatch({ type: "CREATE_TODO", payload: payload })
const response = await todoService.createTodo(payload)
dispatch({ type: "CREATE_TODO_SUCCESS", payload: response })
} catch (err) {
dispatch({
type: "CREATE_TODO_ERROR",
payload: { error: "Cannot create todo. Please try again later" }
})
}
}
}
export const toggleTodo = (payload: ToggleTodo) => {
return async (dispatch: Dispatch<TodoAction>): Promise<void> => {
try {
const response = await todoService.updateTodo(payload.id, { complete: payload.complete })
dispatch({ type: "TOGGLE_TODO_SUCCESS", payload: response })
} catch (err) {
dispatch({
type: "TOGGLE_TODO_ERROR",
payload: { error: `${err}` }
})
}
}
}
...
}
all code is here: https://github.com/maridoroshuk/todos-ts
Solution 1:[1]
useEffect(callback, dependencies) triggers only when data in dependencies changes. In your code, you put useEffect( ... , []), meaning you don't have any dependencies, so the callback function only runs once when the component mounts.
If you want useEffect to run on every update, you need to not put any dependencies: useEffect(...).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | cSharp |
