Javascript 在功能组件内部传递函数状态
一般来说,我对react和typescript还很陌生,所以可能还有一些其他问题我没有看到。我发现的大多数教程都是针对基于类的组件的,而不是针对函数式组件的,这使得它更加困难 我有一个包含两个复选框的组件。当切换复选框时,我也想将此更新发布到url。目前,切换正在工作,我可以相应地更新状态。问题是,当尝试发布更新时,请求中没有设置更新状态,而是设置了以前的状态 下面是主要的Javascript 在功能组件内部传递函数状态,javascript,reactjs,typescript,semantic-ui-react,Javascript,Reactjs,Typescript,Semantic Ui React,一般来说,我对react和typescript还很陌生,所以可能还有一些其他问题我没有看到。我发现的大多数教程都是针对基于类的组件的,而不是针对函数式组件的,这使得它更加困难 我有一个包含两个复选框的组件。当切换复选框时,我也想将此更新发布到url。目前,切换正在工作,我可以相应地更新状态。问题是,当尝试发布更新时,请求中没有设置更新状态,而是设置了以前的状态 下面是主要的文档组件。我认为问题在于updateDocument函数,因为调用时状态不一定是由setToggles设置的。根据我所读到的
文档
组件。我认为问题在于updateDocument
函数,因为调用时状态不一定是由setToggles
设置的。根据我所读到的,我需要使用回调,但我不确定如何实现这一点
const Document: FC<{ document: IDocument }> = ({document}): ReactElement => {
const [toggles, setToggles] = useState<DocumentToggles>(_documentToggles)
const updateDocument = (uri: string, id: string, desc: string, checked: boolean, expired: boolean) => {
axios.post(uri, {
id: id,
description: desc,
checked: checked,
expired: expired
}).then(response => {
console.log(response.data)
});
}
const handleToggle = (e: FormEvent<HTMLInputElement>, data: any) => {
console.log(data)
if (e.currentTarget !== null) {
const {name, checked} = data;
setToggles(prevState => ({...prevState, [name]: checked}))
// THIS IS NOT WORKING
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
}
}
const handleSubmit = (e: FormEvent) => {
if (e.currentTarget !== null) {
e.preventDefault()
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
}
}
return (
<Container>
<Form onSubmit={handleSubmit}>
<DocumentCheckboxes
checked={toggles.checked}
expired={toggles.expired}
handleToggle={handleToggle}
/>
<Form.Field>
<Button fluid type="submit">
Save
</Button>
</Form.Field>
</Form>
</Container>
);
};
更新:
使用@Ibz提供的更改更新了文档
组件。现在唯一的问题是,如果切换多个切换,那么对更新url的POST
请求将运行两次。仅切换单个组件将无法完成此操作
const Document: FC<{ document: IDocument }> = ({document}): ReactElement => {
const [toggles, setToggles] = useState<DocumentToggles>(_documentToggles)
const updateDocument = (uri: string, id: string, desc: string, checked: boolean, expired: boolean) => {
axios.post(uri, {
id: id,
description: desc,
checked: checked,
expired: expired
}).then(response => {
console.log(response.data)
});
}
const handleToggle = (e: FormEvent<HTMLInputElement>, data: any) => {
console.log(data)
if (e.currentTarget !== null) {
e.preventDefault()
setToggles(prevState => {
const newState = {...prevState, [data.name]: data.checked};
updateDocument('http://example.com/update', document.id, document.description, newState.checked, newState.expired);
return newState;
})
}
}
const handleSubmit = (e: FormEvent) => {
if (e.currentTarget !== null) {
e.preventDefault()
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
}
}
return (
<Container>
<Form onSubmit={handleSubmit}>
<DocumentCheckboxes
checked={toggles.checked}
expired={toggles.expired}
handleToggle={handleToggle}
/>
<Form.Field>
<Button fluid type="submit">
Save
</Button>
</Form.Field>
</Form>
</Container>
);
};
对于useState,不能保证操作是按顺序执行的,因为组件需要重新渲染以获得所有最新状态
setToggles(prevState => ({...prevState, [name]: checked}))
// THIS IS NOT WORKING
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
这意味着使用这段代码,您的组件呈现,并且您在切换中有一些值。当您使用setToggles(…)时,react会将状态更新排队等待下一次渲染,因此当您使用updateDocument时,它将使用先前的toggles值运行
为了解决这个问题,我们通常使用useffect
。这是一个钩子,每当其他值发生变化时,它就会运行一些代码。在您的实例中,您可能需要以下内容:
useEffect(() => {
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
}, [document.id, document.description, toggles.checked, toggles.expired])
useEffect的第二个参数称为依赖项数组
,它是一个值列表,更改后,会导致useEffect中的函数运行
一开始在州里绞尽脑汁可能有点棘手,但我希望这能有所帮助。还有什么问题,请留言。您可以在这里找到更多信息:
({…prevState,[名称]:checked})
名称是否需要用大括号括起来?不幸的是,没有任何东西会立即向我解释为什么它会发送多个post请求。它是否在两个相同的请求时停止?或者数字是否随着每次切换而不断增加?我是在文档
组件中使用useffect
,还是在文档组件中使用handleToggle
函数。React钩子需要在组件的顶层调用,并且通常在所有useState调用之后直接定义useEffect方法。因此,在您的例子中,在const[toggles,setToggles]=useState之后的一行中,根据我的理解,这会产生一个不同的问题。由于更新依赖项数组中的项时会调用useEffect,因此在呈现视图时,每个文档
都会发出POST
请求(在updateDocument
中)。如果调用了handleToggle
,我只想运行updateDocument
。啊,我明白了。您可以尝试将函数传递到setState:setToggles(prevState=>{const newState={…prevState,[name]:checked};updateDocument('http://example.com/update,document.id,document.description,newState.checked,newState.expired);return newState;})
。如果你喜欢的话,我可以把它作为一个单独的答案来发布,谢谢你的帮助!这几乎是工作,基本上是我想要的。但是有一个问题:在切换第二个切换时,无论是选中了还是过期了,都会运行两次更新文档
?我不太确定这是否确实来自updateDocument
,但我可以看到有两个POST
请求。仅切换一个切换时,仅进行一次POST
。我已经编辑了OP,将更新的文档
组件与您的建议一起包含在内。
setToggles(prevState => ({...prevState, [name]: checked}))
// THIS IS NOT WORKING
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
useEffect(() => {
updateDocument('http://example.com/update', document.id, document.description, toggles.checked, toggles.expired)
}, [document.id, document.description, toggles.checked, toggles.expired])