reactjs - React 不会更新 DOM 中的排序项
问题描述
所以当我想在 React 中对数组中的元素进行排序时遇到了问题。
问题不在于排序逻辑,而在于 React 本身,所以每当我想单击一个显示“按难度排序”的按钮时,它都不起作用。但是,当我在同一时刻单击“隐藏”按钮时,DOM 中的元素会完全按照我的意愿进行更新。
是什么导致了这个问题以及如何解决它?谢谢
编辑:代码沙盒链接 https://codesandbox.io/s/tender-rubin-1nq0r
import React, { useState, useEffect } from 'react';
// import { ListProvider } from '../context/listContext.js';
import useAjax from '../custom-hooks/useAjax.js';
import TodoForm from './form.js';
import './todo.scss';
const ToDo = () => {
const [_addItem, _toggleComplete, _getTodoItems, _deleteItems, _hideItems, sorted, list] = useAjax()
useEffect(_getTodoItems, []);
const [currentPage, setCurrentPage] = useState(1)
const [todosPerPage, setTodosPerPage] = useState(3)
const pageNumbers = []
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
let currentTodos = list.slice(indexOfFirstTodo, indexOfLastTodo)
for (let i = 1; i <= Math.ceil(list.length / todosPerPage); i++) {
pageNumbers.push(i);
}
return (
<>
<header>
<h2>
There are {list.filter(item => !item.complete).length} Items To Complete
</h2>
</header>
<section className="todo">
<div>
<TodoForm handleSubmit={_addItem} />
</div>
<div>
<ul>
{currentTodos.map(item => (
<li
className={`complete-${item.complete.toString()}`}
key={item._id}
>
<span onClick={() => _toggleComplete(item._id)}>
{item.text}
</span>
<small>{item.difficulty}</small>
<button onClick={() => _deleteItems(item)}>X</button>
</li>
))}
{
pageNumbers.map(number => {
return (
<button
key={number}
id={number}
onClick={(event) => { setCurrentPage(Number(event.target.id)) }}
>
{number}
</button>
);
})
}
<button onClick={_hideItems}>hide</button>
<button onClick={sorted}>Sort By Difficulty</button>
</ul>
</div>
</section>
</>
);
};
export default ToDo;
// **************************THe custom Hook file it attached below :******************************************
import { useState } from 'react'
import axios from 'axios'
const todoAPI = 'https://api-js401.herokuapp.com/api/v1/todo'
export default () => {
const [list, setList] = useState([])
const _addItem = (item) => {
item.due = new Date()
axios.post(todoAPI, JSON.stringify(item), {
headers: { 'Content-Type': 'application/json' }
})
.then(data => {
setList([...list, data.data])
})
}
const _toggleComplete = id => {
let item = list.filter(i => i._id === id)[0] || {};
if (item._id) {
item.complete = !item.complete;
let url = `${todoAPI}/${id}`;
axios.put(url, JSON.stringify(item), {
headers: { 'Content-Type': 'application/json' }
})
.then(data => {
setList(list.map((listItem) => listItem._id === item._id ? data.data : listItem))
})
}
}
const _getTodoItems = async () => {
let rawData = await axios.get(todoAPI)
let data = rawData.data.results
setList(data)
}
const _deleteItems = async item => {
let url = `${todoAPI}/${item._id}`
let deletedItem = await axios.delete(url)
setList(list.filter((listItem) => listItem._id === deletedItem.data._id ? '' : listItem))
}
const _hideItems = () => {
setList(list.filter(listItem => (
listItem.complete === false
)))
}
const sorted = () => {
setList(list.sort((a, b) => {
return b.difficulty - a.difficulty
}))
}
return [_addItem, _toggleComplete, _getTodoItems, _deleteItems, _hideItems, sorted, list]
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
解决方案
发生这种情况是因为.sort(...)
不返回新数组而是返回相同的数组,即它不是新的对象引用。你必须明确地这样做,这样React才能知道我有一个新的对象引用,这意味着我应该导致一个re-render。
在hide
实现中,您使用.filter(...)
on 会list
为您返回一个新数组,因此您不必显式执行此操作。
useAjax
只需在钩子中更改您的排序实现,如下所示:-
const sorted = () => {
setList([...list.sort((a, b) => {
return b.difficulty - a.difficulty
})])
}
...
是用于创建列表的浅表副本的扩展运算符。
分叉沙箱 - https://codesandbox.io/s/epic-leakey-vr925?file=/src/custom-hooks/useAjax.js
推荐阅读
- git - Git 签出路径规范错误。获取正确路径的命令
- rust - 如何在构建过程中包含文件夹?
- php - Codeigniter:模型未出现错误:未定义属性:CI_Loader
- reactjs - 仅当我重新启动项目时,React 才呈现我的组件
- r - 通过 insertUI 重置动态生成的小部件的输入字段
- android - Koin:NoBeanDefFoundException,检查你的模块定义
- c# - 尝试从 NamedPipeClientStream 写入 NamedPipeServerStream 时如何修复“断管”错误
- css - 如何为 helperText 材质 ui 分配颜色以突出显示 TextField 中的错误
- python - 用于删除多个文件中的重复行的 Python 脚本
- ruby-on-rails-3 - 如何在 RSpec 中使用“expect().to receive()”过滤掉许多其他方法调用