我有一些代码可以为外部 JSON API 返回的每个条目创建一个 react-final-form
表单。
我试图使用变量 i
来设置 Control
的 Input
脉轮组件的名称。 (这个组件的定义是从 react-final-form with chakra example here 复制的)。 i
将在 API 中数组项的循环中递增。这以某种方式导致无限循环。 (示例代码中对return语句中的这段代码进行了注释)
但是,如果我只是在没有 i
变量的情况下设置名称,则一切正常。
我想了解为什么使用 i
会导致无限循环?
我想以某种方式使用 i
会导致 Form
以某种方式改变状态/重新渲染,但我现在确定如何/为什么会发生这种情况?
这是重现问题的笔: https://codepen.io/growinman/pen/GRmGyxX?editors=1010
(代码原样工作正常,但如果我使用带注释的 return 语句,则会导致无限循环)
任何帮助将不胜感激!
这是代码的内联副本:
import * as finalForm from "https://cdn.skypack.dev/final-form@4.20.2";
import { Form, useField } from "https://cdn.skypack.dev/react-final-form@6.5.3";
import * as reactRouterDom from "https://cdn.skypack.dev/react-router-dom@5.2.0";
import * as React from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
import { Input } from "https://cdn.skypack.dev/@chakra-ui/input@1.2.8";
import { VStack } from "https://cdn.skypack.dev/@chakra-ui/react@1.6.5";
import { Heading } from "https://cdn.skypack.dev/@chakra-ui/layout@1.4.7";
import { FormControl, FormErrorMessage } from "https://cdn.skypack.dev/@chakra-ui/form-control@1.3.8";
async function handleErrors(response) {
if (!response.ok) {
throw await response.json();
}
return response;
}
const makeGetRequest = (requestUrl) => {
const requestOptions = {
method: 'GET'
}
return fetch(requestUrl, requestOptions)
.then(handleErrors)
.then((response) => {
return response.json()
})
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const onSubmit = async values => {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
const ProductReview = (props) => {
let i=0;
console.log('rendering')
const [unreviewedProducts, setUnreviewedProducts] = React.useState({})
React.useEffect(
() => {
console.log('In useeffect')
makeGetRequest('https://mocki.io/v1/aea3b014-5a38-4366-a71c-87b2e53eb07c').then(
// Create a map for unreviewedProducts from the 'unreviewedProductsJson' array, keyed by the uuid
(unreviewedProductsJson) => {
setUnreviewedProducts(
unreviewedProductsJson.reduce(
(mapSoFar, currentObj) => ({...mapSoFar, [currentObj.uuid]: currentObj}), {}
)
)
}
)
},
[]
)
return (
<>
<Heading as="h1" fontSize={[16,32]} textAlign="center" marginTop="20px">
Products
</Heading>
<VStack
alignItems="stretch"
margin="20px auto 0 auto"
w="80%"
maxW="600px"
>
{
Object.values(unreviewedProducts).map((unreviewedProduct) => {
console.log('In map()')
return (
<Form
key={unreviewedProduct.uuid}
onSubmit={onSubmit}
validate={() => {}}
render={({
handleSubmit,
form,
errors,
submitting,
pristine,
values
}) => {
console.log('In render')
console.log(i)
i = i + 1
return (
<VStack
marginTop="103px"
>
<InputControl name={unreviewedProduct.uuid} placeholder="Website" />
</VStack>
)
// return (
// <VStack
// marginTop="103px"
// >
// <InputControl name={i} placeholder="Website" />
// </VStack>
// )
}
}
/>
)
})
}
</VStack>
</>
)
}
// These were mainly copied from the chakra-ui/react-final-form example
// from here: https://final-form.org/docs/react-final-form/examples/chakra
const Control = ({ name, ...rest }) => {
const {
meta: { error, touched }
} = useField(name, { subscription: { touched: true, error: true } })
return <FormControl {...rest} isInvalid={error && touched} />
}
const Error = ({ name }) => {
const {
meta: { error }
} = useField(name, { subscription: { error: true } })
return <FormErrorMessage>{error}</FormErrorMessage>
}
const InputControl = ({ name }) => {
const { input, meta } = useField(name)
return (
<>
<Control name={name} my={4}>
<Error name='s' />
<Input
{...input}
isInvalid={meta.error && meta.touched}
id={name}
/>
</Control>
</>
)
}
ReactDOM.render(<ProductReview />, document.getElementById('root'))