【发布时间】:2022-10-07 03:07:44
【问题描述】:
在写这篇文章时,我意识到解决方案是什么
我知道为什么会这样。当我尝试使用 useSelector 获取待办事项列表然后映射到列表时,就会发生这种情况。但是,映射不是问题,而是在 map 函数上返回一个反应组件。如果我不返回功能组件而是使用 HTML,它就可以正常工作。因此,从我的 POV 来看,问题是返回一个反应功能组件,同时在地图功能上将道具传递给它。
这是我的家庭组件的代码:
import Input from \'../components/Input\';
import TodoForm from \'../components/TodoForm\';
function Home() {
document.title = \"MyTodo | Home\"
return (
<div className=\"App\">
<h1>MyTodo</h1>
<Input />
<TodoForm />
</div>
);
}
export default Home;
在按键按下时分派操作的输入组件:
import {useState} from \'react\'
import { useDispatch } from \'react-redux\';
import { todoActions } from \'../store/todo\';
const Input = () => {
const [inputText, setInputText] = useState(\"\");
const dispatch = useDispatch();
const handleChange = (e) => setInputText(e.target.value)
const handleKeyPress = (event) => {
if (event.code === \"Enter\") {
// if the expression is false, that means the string has a length of 0 after stripping white spaces
const onlyWhiteSpaces = !inputText.replace(/\\s/g, \"\").length;
!onlyWhiteSpaces &&
dispatch(
todoActions.addTask({ label: inputText, done: false })
);
setInputText(\"\");
}
};
return (
<input
type=\"text\"
onKeyDown={(e) => handleKeyPress(e)}
onChange={(e) => handleChange(e)}
value={inputText}
/>
);
}
export default Input
我使用useSelector 的 TodoForm 从 redux 存储中获取待办事项列表并通过它进行映射:
import { useSelector } from \"react-redux\";
import { v4 as uuidv4 } from \"uuid\";
import TodoTask from \"./TodoTask\";
const TodoForm = () => {
const tasks = useSelector((state) => state.todo.taskList);
const renderedListItems = tasks.map((task, index) => {
return (
<TodoTask
key={uuidv4()}
task={task}
targetIndex={index}
/>
);
});
return <div className=\"container\">{renderedListItems}</div>;
};
export default TodoForm;
最后是 TodoTask 组件,它是上面 map 函数中返回的子组件:
import { useDispatch } from \"react-redux\";
import { todoActions } from \"../store/todo\";
const TodoTask = ({ task, targetIndex }) => {
const {text, done} = task;
console.log(\"Task: \", task);
const dispatch = useDispatch()
const removeTask = dispatch(todoActions.deleteTask(targetIndex))
return (
<div
className=\"alert alert-primary d-flex justify-content-between\"
role=\"alert\"
>
{text}
<button type=\"button\" className=\"btn-close\" onClick={()=>removeTask}></button>
</div>
);
};
export default TodoTask;
这是我第一次遇到这个问题,我知道这与 redux 以及 useSelector hook 如何强制组件重新渲染有关。因此 useSelector 正在重新渲染 TodoForm 组件,并且由于我们正在映射并返回另一个组件,因此该组件也同时被渲染。至少,我是这么理解的。让我知道我是否错了。
我尝试过的事情:
- 在 React.memo 中包装 TodoTask。在某处看到它作为此类问题的可能解决方案,但这不起作用。
- 将
shallowEqual作为TodoForm useSelector 的第二个参数传递。这确实可以防止页面进入无限循环,但任务显示为空但正在添加到 redux 存储。但是,使用这种方法,第一个警告仍然出现,并且TodoTask 组件中的控制台日志不执行。
标签: reactjs redux react-hooks react-redux