我有一个组件(卡),该组件具有使用Postgres在localhost数据库中跟踪的复选框。当我选中或取消选中该框时,条目将被放入networkusers表中。问题是,当我选中或取消选中该框,然后单击一个按钮以呈现其他组件,然后又将其与复选框一起返回到Card组件时,这些框未显示更新后的复选框。但是,如果我注销并重新登录,则所有框都将更新并与数据库同步。因此,如何更改以下组件中的复选框,如何使该组件呈现(或再次获取?)? TY。
import React, { useState } from "react";
const onUpdateCB = (ischecked, loginuser, userid, setisChecked,handleCheck,event) => {
console.log(ischecked, loginuser, userid);
fetch('http://localhost:3000/cb', {
method: 'post',
headers: {'Content-Type':'application/json'},
body:JSON.stringify({
loginuser,
userid,
ischecked: ischecked
})
}).then(setisChecked(ischecked));
};
const Card = props => {
const [isChecked, setisChecked] = useState(props.ischecked);
return (
<div
className="pointer bg-light-green dib br3 pa3 ma2 shadow-5"
onClick={() => props.handleClick(props.id)}
//onClick={(e) => e.stopPropagation()}
>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
My Network
<input
className="largeCheckbox"
type="checkbox"
checked={isChecked}
onClick={(event) =>
onUpdateCB(!isChecked, props.loginuser.id, props.id, setisChecked,event.stopPropagation())
}
/>
</div>
</div>
);
};
export default Card;
网络阵列
import React from "react";
import Card from "./Card";
const NetworkArray = ({
network,
networkusers,
handleChange,
handleClick,
loginuser
}) => {
console.log("in network array", networkusers);
const cardComponent = network.map((user, i) => {
const ischecked = networkusers.filter(n => {
var nw = n.id === loginuser.id && n.connections === network[i].id;
return nw;
});
console.log("i'm checked", ischecked);
return (
<Card
key={network[i].id}
name={network[i].firstname + " " + network[i].lastname}
company={network[i].company}
phone={network[i].phone}
email={network[i].email}
city={network[i].city}
ischecked={ischecked.length}
handleChange={handleChange}
handleClick={handleClick}
id={network[i].id}
loginuser={loginuser}
/>
);
});
return <div>{cardComponent}</div>;
};
export default NetworkArray;
答案 0 :(得分:3)
首先,在React Application中必须遵循两个原则。
1。不要在任何应用程序状态下存储两个事实来源。
此刻,卡存储了自己的状态isChecked
,并且Network
上方的某个位置也已从数据库中获取值,并且isChecked
也传递给了卡组件。
拥有多个真理来源不是很好,通常以后会再次困扰我们,因此规则1。不要拥有多个真理来源
Fix #1: remove "isChecked" state from Card.
import React, { useState } from "react";
const onUpdateCB = (ischecked, loginuser, userid) => {
console.log(ischecked, loginuser, userid);
fetch('http://localhost:3000/cb', {
method: 'post',
headers: {'Content-Type':'application/json'},
body:JSON.stringify({
loginuser,
userid,
ischecked: ischecked
})
});
};
const Card = props => {
const { ischecked } = props;
return (
<div
className="pointer bg-light-green dib br3 pa3 ma2 shadow-5"
onClick={() => props.handleClick(props.id)}
//onClick={(e) => e.stopPropagation()}
>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
My Network
<input
className="largeCheckbox"
type="checkbox"
checked={ischecked}
onClick={(event) =>
onUpdateCB(!isChecked, props.loginuser.id, props.id)
}
/>
</div>
</div>
);
};
export default Card;
....实际上,第一个主体应足以解决您的问题。但是以防万一你很好奇。
2。在渲染后进行副作用(componentDidMount,componentDidUpdate,useEffect)。
流程应该像这样,
event => setState => render => side-effect
假设您的卡组件是独立的,不会从道具中获得价值。
const onUpdateCB = (ischecked, loginuser, userid) => {
return fetch('http://localhost:3000/cb', {
method: 'post',
headers: {'Content-Type':'application/json'},
body:JSON.stringify({
loginuser,
userid,
ischecked: ischecked
})
});
}
const Card = props => {
const [data, setData] = useState({});
// 2: set new state
const onSelectCheckbox = (ischecked) => {
const newData = { ...data, ischecked };
setData(newData);
}
useEffect(() => {
// 4. Watch if data.ischecked change, if yes perform side effect (call api)
onUpdateCB(data.ischecked, props.loginuser.id, props.id);
}, [data.ischecked]);
// 3. re-render when data change.
const { name, company, phone, email, city, ischecked } = data;
return (
<div className="pointer bg-light-green dib br3 pa3 ma2 shadow-5">
<div>
<h3>{name}</h3>
<p>{company}</p>
<p>{phone}</p>
<p>{email}</p>
<p>{city}</p>
</div>
<div>
My Network
<input
className="largeCheckbox"
type="checkbox"
checked={ischecked}
onClick={(event) =>
onSelectCheckbox(!isChecked) // 1. User interact with checkbox
}
/>
</div>
</div>
);
};
答案 1 :(得分:1)
我相信,问题出在Card
的父母中。它会传递已检查状态(props.ischecked
)的初始值,因此您可能需要将状态更改通知它,并使您的Card
不受其自身状态的完全控制。
如何执行此操作有几种选择,具体取决于您使用的状态管理策略。
const Parent = () => {
const [ ischecked, setChecked ] = useState(false);
return (
<Card ischecked={ ischecked } ... />
);
}
在这种情况下,请提供回调以将状态更改为Card
组件:
const Parent = () => {
...
return (
<Card ischecked={ ischecked } onCheckedChange={ setChecked } ... />
);
}
...
const Card = (props) => {
...
return (
<div ...>
...
<input
...
checked={props.ischecked}
onClick={(event) =>
onUpdateCB(!isChecked, props.loginuser.id, props.id, props.onCheckedChange,event.stopPropagation())
}
/>
</div>
</div>
);
}
import { setChecked } from './actions';
const Card = props => {
// the same as above
}
export default connect(state => ({
ischecked: state.ischecked
}), {
onCheckedChange: setChecked
})(Card);
P.S。此外,您的onUpdateCB()
方法中有错别字-您应该使用函数作为Promise回调:
}).then(
() => setisChecked(ischecked)
);
当前,您只是同时设置了选中状态。
答案 2 :(得分:0)
让我仔细澄清一下。
第一个渲染。
第二个渲染。
然后第二次渲染同一张Card时,再次
所以我们看到了Card之所以不显示更新的 isChecked 的原因,因为道具被选中未被更改。
解决此问题的方法是确保不仅对本地状态,而且对道具的检查已成功更新。我不确定如何在您的代码中使用此功能,因为被选中是由许多其他道具计算得出的,请自己尝试并祝您好运。
最后,为什么退出并登录后没有出现此问题?因为通过这种方式,父级中的道具已完全重新加载了包括被检查相关片段的更新数据。这样就得到了复选框的更新值。就是这样。
答案 3 :(得分:0)
在React中,卸载组件时,它会释放其内部状态。
因此,当您回到它上面时,必须确保卡中的props.ischecked
具有更新的值,该值来自于NetworkArray的network
属性。
因此,当您回到该组件时,一旦完成network
,就需要确保fetch
道具是不同的。
通常,在NetworkArray上方,您将在ComponentDidMount中进行获取以更新网络道具。
这是整个代码的样子:
import React, { useState } from "react";
import Card from "./Card";
class ComponentAboveNetworkArray extends React.Component {
constructor(props) {
super(props)
this.state = {
/* ... */
network: []
}
}
componentDidMount() {
fetch('http://localhost:3000/cb')
.then(response => response.json())
.then(json => this.setState({network: json.network}))
}
return (
<NetworkArray /* ... */ network={this.state.network} />
)
}
const NetworkArray = ({
network,
networkusers,
handleChange,
handleClick,
loginuser
}) => {
console.log("in network array", networkusers);
const cardComponent = network.map((user, i) => {
const ischecked = networkusers.some(n => {
var nw = n.id === loginuser.id && n.connections === network[i].id;
return nw;
});
console.log("i'm checked", ischecked);
return (
<Card
key={network[i].id}
name={network[i].firstname + " " + network[i].lastname}
company={network[i].company}
phone={network[i].phone}
email={network[i].email}
city={network[i].city}
ischecked={ischecked}
handleClick={handleClick}
id={network[i].id}
loginuser={loginuser}
/>
);
});
return <div>{cardComponent}</div>;
};
export default NetworkArray;