不确定如何在stackoverflow内将其变为可重复的示例,但我们有以下React组件,该组件创建SVG图形,具有可编辑的标题文本(可以单击文本进行编辑并键入编辑文本)利用foreignObject
和FormControl
import { FormControl } from 'react-bootstrap';
function OurGraph({ headerText }) {
const [graphText, setGraphText] = useState(headerText);
// create editable header
const ourHeader =
(<foreignObject width='100%' height='40'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<FormControl
className='modal-input no-style'
type='text'
value={graphText}
onChange={e => setGraphText(e.target.value)}
name='subheader'
placeholder=''
/>
</div>
</foreignObject>);
// and return
return (<svg>{ourHeader}</svg>);
}
,我们有这个父组件为OurGraph
组件更新默认的headerText
:
function Parent() {
const [button, setButton] = useState(true);
const buttonElement =
(<button onClick={() => setButton(!button)}>
CLICK ME
</button>);
return (
{buttonElement}
<OurGraph headerText={button === true ? 'true text' : 'false text'} />
)
}
这是如此接近工作的预期…当组件最初呈现时,true text
显示为SVG中的文本,很好!当我们点击文本时,文本是可编辑的,很好!
问题是,当我们点击CLICK ME
按钮时,它将OurGraph
中的headerText
道具从true text
更改为false text
,OurGraph
组件中的SVG中的文本不即使prop值成功更新到false text
,也要更新到false text
。
为什么会这样?我们如何解决这个问题,使变化的道具值反映在SVG的表单控件的文本?我们认为新的headerText
值会导致const [graphText, setGraphText] = useState(headerText);
为graphText
设置一个新的值,但是当headerText
道具从true text
变为false text
时,graphText
并没有改变。
编辑-虽然它看起来像一个反模式立即setState()从一个道具值,但我们需要graphText作为一个变量的状态,因为它是在FormControl中更新的,我们希望道具值headerText
是graphText
的默认值。最重要的是,无论何时headerText
发生变化,我们都希望用headerText
传递的新prop值覆盖graphText
中FormControl
设置的任何值。
这是一个典型的反模式示例。React不会重新初始化状态。为了使它工作,你可以这样做:
import { FormControl } from 'react-bootstrap';
import {useEffect} from 'react';
function OurGraph({ headerText }) {
const [graphText, setGraphText] = useState(headerText);
useEffect(()=>{
setGraphText(headerText)
},[headerText])
// create editable header
const ourHeader =
(<foreignObject width='100%' height='40'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<FormControl
className='modal-input no-style'
type='text'
value={graphText}
onChange={e => setGraphText(e.target.value)}
name='subheader'
placeholder=''
/>
</div>
</foreignObject>);
// and return
return (<svg>{ourHeader}</svg>);
}
此外,更好的方法是将此状态引入上下文并从上下文导出onChange函数,并使用自定义钩子对其进行操作。