我有一个React表单和正确管理状态的问题。我有一个表单(模态)的时间输入字段。初始值被设置为getInitialState中的状态变量,并从父组件传入。这本身就很好。
当我想通过父组件更新默认的start_time值时,问题就来了。更新本身在父组件中通过setState start_time: new_time进行。然而,在我的表单中,默认的start_time值从未改变,因为它只在getInitialState中定义了一次。
我尝试使用componentWillUpdate强制通过setState start_time: next_props改变状态。start_time,这实际上是工作的,但它给了我Uncaught RangeError:最大调用堆栈大小超过错误。
我的问题是,在这种情况下,更新状态的正确方法是什么?我是不是想错了?
当前代码:
@ModalBody = React.createClass
getInitialState: ->
start_time: @props.start_time.format("HH:mm")
#works but takes long and causes:
#"Uncaught RangeError: Maximum call stack size exceeded"
componentWillUpdate: (next_props, next_state) ->
@setState(start_time: next_props.start_time.format("HH:mm"))
fieldChanged: (fieldName, event) ->
stateUpdate = {}
stateUpdate[fieldName] = event.target.value
@setState(stateUpdate)
render: ->
React.DOM.div
className: "modal-body"
React.DOM.form null,
React.createElement FormLabelInputField,
type: "time"
id: "start_time"
label_name: "Start Time"
value: @state.start_time
onChange: @fieldChanged.bind(null, "start_time")
@FormLabelInputField = React.createClass
render: ->
React.DOM.div
className: "form-group"
React.DOM.label
htmlFor: @props.id
@props.label_name + ": "
React.DOM.input
className: "form-control"
type: @props.type
id: @props.id
value: @props.value
onChange: @props.onChange
来自react文档:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
道具改变时擦除状态是一种反模式
自React 16起,componentWillReceiveProps已弃用。从react文档来看,在这种情况下推荐的方法是使用
Fully controlled component: the ParentComponent of the ModalBody will own the start_time state. This is not my prefer approach in this case since i think the modal should own this state.
Fully uncontrolled component with a key: this is my prefer approach. An example from react documentation : https://codesandbox.io/s/6v1znlxyxn . You would fully own the start_time state from your ModalBody and use getInitialState just like you have already done. To reset the start_time state, you simply change the key from the ParentComponent
我使用功能组件和useEffect钩子提出了以下解决方案:
它通过使用useEffect钩子监视props中的控制属性来工作
const { useEffect, useState } = React
const Child = (props) => {
const [bgColor, setBgColor] = useState(props.bgColor);
const { children } = props;
useEffect(() => {
setBgColor(props.bgColor);
}, [props.bgColor]);
return (
<div style={{ height: "100px", width: "100px", backgroundColor: bgColor }}>{children}</div>
)
}
const Parent = (props) => {
const [childControllingProp, setChildControllingProp] = useState(props.childControllingProp);
const { title } = props;
const inputRef = React.createRef();
return (
<>
<input ref={inputRef} type="text" onChange={() => setChildControllingProp(inputRef.current.value)}/>
<Child bgColor={childControllingProp}>{title}</Child>
</>
)
}
$(document).ready(() => {
ReactDOM.render(
<Parent title="Title" childControllingProp="blue"/>,
document.querySelector("#root")
);
})
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<div id="root"></div>
来自react文档:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
道具改变时擦除状态是一种反模式
自React 16起,componentWillReceiveProps已弃用。从react文档来看,在这种情况下推荐的方法是使用
Fully controlled component: the ParentComponent of the ModalBody will own the start_time state. This is not my prefer approach in this case since i think the modal should own this state.
Fully uncontrolled component with a key: this is my prefer approach. An example from react documentation : https://codesandbox.io/s/6v1znlxyxn . You would fully own the start_time state from your ModalBody and use getInitialState just like you have already done. To reset the start_time state, you simply change the key from the ParentComponent