我正在尝试使用 React 中的 onClick 事件从列表中删除一个项目(const removeItem(。状态由钩子管理。我知道我删除项目的方式还不正确(我将名称设置为 null(,但这不是问题所在。
将用户设置为 null 后(我更新了用户对象(,我希望发生渲染(useEffect(,但事实并非如此。如果我切换组件并返回到这个组件,它可以工作,但是当单击 X 按钮时,视图中没有任何反应。
组件主页:
import React, { Suspense, useState, useEffect } from "react";
const Home = props => {
const [users, setUsers] = useState(props.users);
console.log(users);
useEffect(() => {}, [users]);
const addItem = e => {
users.push(e);
console.log(e);
e.preventDefault();
};
const removeItem = item => {
users.forEach(user => {
if (user.id === item) {
user.name = null;
}
});
console.log(users);
setUsers(users);
};
return (
<div className="Home">
<form className="form" id="addUserForm">
<input
type="text"
className="input"
id="addUser"
placeholder="Add user"
/>
<button className="button" onClick={addItem}>
Add Item
</button>
</form>
<ul>
{users.map(item => {
return (
<>
<li key={item.id}>{item.name + " " + item.count}</li>
<button className="button" onClick={() => removeItem(item.id)}>
X
</button>
</>
);
})}
</ul>
</div>
);
};
export default Home;
我如何获得我的用户对象:
import React from "react";
const LotsOfUsers =[...Array(100).keys()].map((item, key) => item = {
name : `User ${key}`,
id: key,
count: 0
})
export default LotsOfUsers;
主要应用:
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
import Home from "./Home"
import CTX from './store'
import LotsOfUsers from "./LotsOfUsers";
export default function App() {
return (
<CTX.Provider value={{}}>
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
<Route path="/">
<Home users={LotsOfUsers} text="hello world"/>
</Route>
</Switch>
</div>
</Router>
</CTX.Provider>
);
}
function About() {
return <h2>About</h2>;
}
function Topics() {
let match = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
{/* The Topics page has its own <Switch> with more routes
that build on the /topics URL path. You can think of the
2nd <Route> here as an "index" page for all topics, or
the page that is shown when no topic is selected */}
<Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route>
<Route path={match.path}>
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
function Topic() {
let { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>;
}
查看您的代码,我注意到您在不使用setUsers
的情况下更改了 2 次users
。
const addItem = e => {
users.push(e); // <--- here
console.log(e);
e.preventDefault();
};
const removeItem = item => {
users.forEach(user => {
if (user.id === item) {
user.name = null; // <--- here
}
});
console.log(users);
setUsers(users);
};
这样,您正在 更新您的users
,而不会让反应知道它。在这两种情况下,您都必须使用setUsers
更新users
,而不是直接改变数组。
const addItem = e => {
setUsers(users.concat(e)); // sidenote: if e is your event, then you might be looking for e.target.value here
console.log(e);
e.preventDefault();
};
const removeItem = item => {
setUsers(users.filter(user => user.id !== item));
};
.concat()
和.filter()
都使用您的users
数组,并根据要应用的更改返回一个新数组,然后由setUsers
用于更新您的users
。
所以,扩展一下我在removeItem
上实际做的事情是:
const removeItem = item => {
const newUsers = users.filter(user => user.id !== item); // users remains untouched
setUsers(newUsers);
};
此外,不需要useEffect
钩子即可使此方案正常工作。
我希望这能解决你的问题。
你犯了反应宇宙的根本罪。"突变" 的状态。
const removeItem = item => {
users.forEach(user => {
if (user.id === item) {
user.name = null; // <--- HERE
}
});
console.log(users);
setUsers(users);
};
检查此代码沙箱以获取此问题的工作演示。 https://codesandbox.io/s/jovial-panini-unql4
反应协调器检查 2 个对象是否相等,并且由于您刚刚变异并设置了它注册为同一对象的值,并且不会触发状态更改。因此,视图不会被重新渲染,也不会触发 useEffect。