React 控制的 MUI 表单字段组件
React controlled MUI form field components
我觉得我错过了明显的东西,但我似乎找不到另一个 post 来解决我遇到的问题。我试图让最终用户能够为对象设置位置,但可以将信息输入表单或单击地图上的位置。我有一个包含三个组件的反应页面。
- 包含其他两个组件的父容器组件。
import {useState} from 'react';
import Box from '@mui/material/Box';
import ObjSetLocationForm from './ObjSetLocationForm';
import ObjSetLocationMap from './ObjSetLocationMap';
export default function LoadSetLocationSet( props ) {
const [prevLat, setPrevLat] = useState("43.5666694");
const [prevLng, setPrevLng] = useState("-101.0716746");
const [newLat, setNewLat] = useState();
const [newLng, setNewLng] = useState();
function setCoords(coords){
setNewLat(coords.lat);
setNewLng(coords.lng);
}
return(
<Box>
<ObjSetLocationForm prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
<ObjSetLocationMap prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
</Box>
);
}
- 在地图 A 上显示单个点并允许最终用户单击地图以将点设置到新位置 (lat/lng) 的地图组件,并且是父容器的子项.我不会 post 这个组件的所有代码,因为它相当大,但重要的部分是当用户点击地图时,新的 lat/lng 值通过调用传递回父组件setCoords 函数就像这样。
props.setCoordsFx({lat: e.lngLat.lat, lng: e.lngLat.lng});
我已经验证它工作正常并且正确地传递了值。
- 一个 Form 组件,它是父容器的第二个子组件,允许最终用户输入 Lat/Lng 来更改地图上单个点的位置。这个组件是我遇到问题的地方。我有两个 html 形式的 MUI TextField,我想在用户单击地图时将其设置为 lat/lng 值。当我 运行 通过调试器时,我可以看到值从父级传递给这个组件,我什至可以看到控制组件的状态值正在设置,但 TextFields 值永远不会改变。
import {useState, useEffect, useContext} from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
export default function LoadSetLocationSet( props ) {
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
function handleSubmit(e) {
e.preventDefault();
// Save values to DB.
}
return(
<Box>
<form id="SelLocationForm" onSubmit={handleSubmit}>
<Box sx={{textAlign:'center'}}>
<Typography variant="h6" sx={{display:'inline'}}>Current Location</Typography>
<Box sx={{display:'flex', alignItems:'center', justifyContent:'center'}}>
<Stack direction="row" spacing={3}>
<Box>
<Box>
<Typography>Latitude</Typography>
</Box>
<Box>
<Typography>{props.prevLat}</Typography>
</Box>
</Box>
<Box>
<Box>
<Typography>Longitude</Typography>
</Box>
<Box>
<Typography>{props.prevLng}</Typography>
</Box>
</Box>
</Stack>
</Box>
</Box>
<Box sx={{textAlign:'center', pt:2}}>
<Typography variant="h6" sx={{mb:2}}>Enter the Latitude and Longitude or click the new location on the map</Typography>
<Typography variant="h6" sx={{display:'inline'}}>New Location</Typography>
<Box sx={{display:'flex', alignItems:'center', justifyContent:'center'}}>
<Stack direction="row" spacing={3}>
<Box>
<TextField
id="tbLatitude"
label="Latitude"
type="text"
size="small"
value={newLat}
onChange={(e) => {setNewLat(e.target.value);}}
/>
</Box>
<Box>
<TextField
id="tbLongitude"
label="Longitude"
type="text"
size="small"
value={newLng}
onChange={(e) => {setNewLng(e.target.value);}}
/>
</Box>
<Box sx={{display:'flex', alignItems:'center', justifyItems:'center'}}>
<Button variant="contained" type="submit">Set</Button>
</Box>
</Stack>
</Box>
</Box>
</form>
</Box>
);
}
如您所见,我正在尝试使用受控的 TextField。所以这是我的 questions/problems:
如果将默认值设置为 prop 值是“反模式”,如果表单字段是受控表单字段,我应该如何设置默认值?
正如我之前所说,当用户单击地图上的某个位置时,它应该刷新表单子组件并将我控制的表单字段的值设置为传入的值,但这不起作用.我怎样才能做到这一点?
我以为我理解了一些事情,因为我现在已经做了一些反应,但我似乎迷路了。抱歉新手问题。
在您的 LoadSetLocationSet
中,您将 newLat
和 newLng
作为道具传递。你还应该传入 setNewLat
和 setNewLng
作为道具。
问题是你在两个地方定义了newLat
和newLng
:
export default function LoadSetLocationSet( props ) {
const [prevLat, setPrevLat] = useState("43.5666694");
const [prevLng, setPrevLng] = useState("-101.0716746");
const [newLat, setNewLat] = useState();
const [newLng, setNewLng] = useState();
和
export default function LoadSetLocationSet( props ) {
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
这会导致问题,因为您实际上只需要 该数据的一个真实来源,如果您试图跟踪该状态,事情就会变得混乱和混乱两个不同的地方。相反,仅在一个地方跟踪newLat
和newLng
。在 React 中,数据流从父级向下流向子级,因此我们经常希望 lift state up
从子表单中删除这些行:
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
然后在父级中我们将把 setNewLat
和 setNewLng
作为 props 传递给表单:
<ObjSetLocationForm prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} setNewLat={setNewLat} setNewLng={setNewLng} />
<ObjSetLocationMap prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
然后您只需调整 TextFields
中的 onChange
函数即可使用作为 props 传入的 setNewLat
和 setNewLng
函数。您还需要更改 value
以使用从 props 传递的数据,以便设置这些字段的 default/initial 值:
<TextField
id="tbLatitude"
label="Latitude"
type="text"
size="small"
value={props.newLat}
onChange={(e) => {props.setNewLat(e.target.value);}}
/>
</Box>
<Box>
<TextField
id="tbLongitude"
label="Longitude"
type="text"
size="small"
value={props.newLng}
onChange={(e) => {props.setNewLng(e.target.value);}}
/>
主要思想是只在一个地方跟踪数据,通常是父组件。即使我们将数据存储在父级中,我们仍然可以通过将 callback 作为道具传递给子级来更新子级的状态。
我觉得我错过了明显的东西,但我似乎找不到另一个 post 来解决我遇到的问题。我试图让最终用户能够为对象设置位置,但可以将信息输入表单或单击地图上的位置。我有一个包含三个组件的反应页面。
- 包含其他两个组件的父容器组件。
import {useState} from 'react';
import Box from '@mui/material/Box';
import ObjSetLocationForm from './ObjSetLocationForm';
import ObjSetLocationMap from './ObjSetLocationMap';
export default function LoadSetLocationSet( props ) {
const [prevLat, setPrevLat] = useState("43.5666694");
const [prevLng, setPrevLng] = useState("-101.0716746");
const [newLat, setNewLat] = useState();
const [newLng, setNewLng] = useState();
function setCoords(coords){
setNewLat(coords.lat);
setNewLng(coords.lng);
}
return(
<Box>
<ObjSetLocationForm prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
<ObjSetLocationMap prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
</Box>
);
}
- 在地图 A 上显示单个点并允许最终用户单击地图以将点设置到新位置 (lat/lng) 的地图组件,并且是父容器的子项.我不会 post 这个组件的所有代码,因为它相当大,但重要的部分是当用户点击地图时,新的 lat/lng 值通过调用传递回父组件setCoords 函数就像这样。
props.setCoordsFx({lat: e.lngLat.lat, lng: e.lngLat.lng});
我已经验证它工作正常并且正确地传递了值。
- 一个 Form 组件,它是父容器的第二个子组件,允许最终用户输入 Lat/Lng 来更改地图上单个点的位置。这个组件是我遇到问题的地方。我有两个 html 形式的 MUI TextField,我想在用户单击地图时将其设置为 lat/lng 值。当我 运行 通过调试器时,我可以看到值从父级传递给这个组件,我什至可以看到控制组件的状态值正在设置,但 TextFields 值永远不会改变。
import {useState, useEffect, useContext} from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
export default function LoadSetLocationSet( props ) {
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
function handleSubmit(e) {
e.preventDefault();
// Save values to DB.
}
return(
<Box>
<form id="SelLocationForm" onSubmit={handleSubmit}>
<Box sx={{textAlign:'center'}}>
<Typography variant="h6" sx={{display:'inline'}}>Current Location</Typography>
<Box sx={{display:'flex', alignItems:'center', justifyContent:'center'}}>
<Stack direction="row" spacing={3}>
<Box>
<Box>
<Typography>Latitude</Typography>
</Box>
<Box>
<Typography>{props.prevLat}</Typography>
</Box>
</Box>
<Box>
<Box>
<Typography>Longitude</Typography>
</Box>
<Box>
<Typography>{props.prevLng}</Typography>
</Box>
</Box>
</Stack>
</Box>
</Box>
<Box sx={{textAlign:'center', pt:2}}>
<Typography variant="h6" sx={{mb:2}}>Enter the Latitude and Longitude or click the new location on the map</Typography>
<Typography variant="h6" sx={{display:'inline'}}>New Location</Typography>
<Box sx={{display:'flex', alignItems:'center', justifyContent:'center'}}>
<Stack direction="row" spacing={3}>
<Box>
<TextField
id="tbLatitude"
label="Latitude"
type="text"
size="small"
value={newLat}
onChange={(e) => {setNewLat(e.target.value);}}
/>
</Box>
<Box>
<TextField
id="tbLongitude"
label="Longitude"
type="text"
size="small"
value={newLng}
onChange={(e) => {setNewLng(e.target.value);}}
/>
</Box>
<Box sx={{display:'flex', alignItems:'center', justifyItems:'center'}}>
<Button variant="contained" type="submit">Set</Button>
</Box>
</Stack>
</Box>
</Box>
</form>
</Box>
);
}
如您所见,我正在尝试使用受控的 TextField。所以这是我的 questions/problems:
如果将默认值设置为 prop 值是“反模式”,如果表单字段是受控表单字段,我应该如何设置默认值?
正如我之前所说,当用户单击地图上的某个位置时,它应该刷新表单子组件并将我控制的表单字段的值设置为传入的值,但这不起作用.我怎样才能做到这一点?
我以为我理解了一些事情,因为我现在已经做了一些反应,但我似乎迷路了。抱歉新手问题。
在您的 LoadSetLocationSet
中,您将 newLat
和 newLng
作为道具传递。你还应该传入 setNewLat
和 setNewLng
作为道具。
问题是你在两个地方定义了newLat
和newLng
:
export default function LoadSetLocationSet( props ) {
const [prevLat, setPrevLat] = useState("43.5666694");
const [prevLng, setPrevLng] = useState("-101.0716746");
const [newLat, setNewLat] = useState();
const [newLng, setNewLng] = useState();
和
export default function LoadSetLocationSet( props ) {
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
这会导致问题,因为您实际上只需要 该数据的一个真实来源,如果您试图跟踪该状态,事情就会变得混乱和混乱两个不同的地方。相反,仅在一个地方跟踪newLat
和newLng
。在 React 中,数据流从父级向下流向子级,因此我们经常希望 lift state up
从子表单中删除这些行:
const [newLat, setNewLat] = useState(props.newLat);
const [newLng, setNewLng] = useState(props.newLng);
然后在父级中我们将把 setNewLat
和 setNewLng
作为 props 传递给表单:
<ObjSetLocationForm prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} setNewLat={setNewLat} setNewLng={setNewLng} />
<ObjSetLocationMap prevLat={prevLat} prevLng={prevLng} newLat={newLat} newLng={newLng} setCoordsFx={setCoords} />
然后您只需调整 TextFields
中的 onChange
函数即可使用作为 props 传入的 setNewLat
和 setNewLng
函数。您还需要更改 value
以使用从 props 传递的数据,以便设置这些字段的 default/initial 值:
<TextField
id="tbLatitude"
label="Latitude"
type="text"
size="small"
value={props.newLat}
onChange={(e) => {props.setNewLat(e.target.value);}}
/>
</Box>
<Box>
<TextField
id="tbLongitude"
label="Longitude"
type="text"
size="small"
value={props.newLng}
onChange={(e) => {props.setNewLng(e.target.value);}}
/>
主要思想是只在一个地方跟踪数据,通常是父组件。即使我们将数据存储在父级中,我们仍然可以通过将 callback 作为道具传递给子级来更新子级的状态。