简体   繁体   English

在 React 中,最初使用 props 的值设置状态,然后使用 FormControl 更新 state

[英]In React, initially setState using value from props, and then update state using FormControl

Not sure how to make this into a reproducible example within stackoverflow, but we have the following React component that creates an SVG graph, that has an editable header text (can click on the text to edit and type to edit the text) leveraging foreignObject and FormControl不确定如何将其变成 stackoverflow 中的可重现示例,但我们有以下 React 组件,它创建一个 SVG 图形,它具有可编辑的 header 文本(可以单击文本进行编辑并键入以编辑文本)利用foreignObjectFormControl

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>);
}

and we have this parent component that updates the default headerText for the OurGraph component:我们有这个父组件来更新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'} />
    )
}

This is so close to working as intended... when the component initially renders, true text shows as the text in the SVG, good, And when we click on the text, the text is editable, good!这与预期的工作非常接近......当组件最初呈现时, true text显示为 SVG 中的文本,很好,当我们单击文本时,文本是可编辑的,很好!

The issue is that when we click on the CLICK ME button, which changes the headerText prop in OurGraph from true text to false text , the text in the SVG in the OurGraph component does not update to false text , even though the prop value does successfully update to false text .问题是,当我们单击CLICK ME按钮时,它会将OurGraph中的headerText属性从true text更改为false textOurGraph组件中 SVG 中的文本不会更新为false text ,即使 prop 值成功完成更新为false text

Why is this?为什么是这样? How can we fix this so that the changing prop value is reflected in the text in the SVG's Form Control?我们如何解决这个问题,以便更改的 prop 值反映在 SVG 表单控件的文本中? We thought that the new headerText value would have led to const [graphText, setGraphText] = useState(headerText);我们认为新的headerText值会导致const [graphText, setGraphText] = useState(headerText); setting a new value for graphText , but graphText is not changing when the headerText prop changes from true text to false text .graphText设置一个新值,但是当headerText属性从true text变为false textgraphText没有改变。

Edit - although it seems like an anti-pattern to immediately setState() from a props value, but we need graphText as a variable in state because it is updated in the FormControl, and we want the prop value headerText to be the default value for graphText .编辑- 虽然从道具值立即设置状态()似乎是一种反模式,但我们需要 graphText 作为 state 中的变量,因为它在 FormControl 中更新,我们希望道具值headerText成为默认值graphText Most importantly, whenever headerText changes, we want to override whatever value may be in graphText set from the FormControl with the new prop value passed in headerText .最重要的是,每当headerText发生变化时,我们都希望使用在headerText中传递的新属性值覆盖FormControlgraphText中设置的任何值。

This is a classic example of an anti-pattern.这是反模式的典型例子。 React does not reinitialize the state. In order to make it work you can do following: React 不会重新初始化 state。为了使其正常工作,您可以执行以下操作:

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>);
 }

Moreover, a better approach would be taking this state into context and exporting the onChange function from context and use custom hook to manipulate it.此外,更好的方法是将此 state 置于上下文中并从上下文中导出 onChange function 并使用自定义挂钩对其进行操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM