我编写了一个组件,该组件应该列出一堆带有相应文本字段的复选框。当您单击复选框时,或在字段中输入内容是为了更新状态。
文本框工作正常,但是当我在字段中键入内容时,它会更新状态确定,但是只要单击键盘,我都会失去焦点。
我意识到这可能是由于没有设置键,所以我向所有内容添加了键,但仍然失去了重点。有一次我尝试在事件中添加stopPropegation,因为我认为这可能会引起问题?我不确定…仍在学习…似乎没有用,所以我也删除了该部分。
似乎仍无法弄清楚是什么原因导致它失去焦点……是否有人对此问题有任何建议/解决方案?
我合并了代码,并切掉了不必要的部分,以使其更易于阅读。有三个相关的JS文件..请参见以下内容:
我仍然是初学者/学习者,因此,如果您有关于此代码任何部分的有用建议,请随时提供。谢谢!
App.js
import React, { Component } from 'react'; import Form from './Form' class App extends Component { constructor() { super(); this.state = { mediaDeliverables: [ {label: 'badf', checked: false, quantity:''}, {label: 'adfadf', checked: false, quantity:''}, {label: 'adadf', checked: false, quantity:''}, {label: 'addadf', checked: false, quantity:''}, {label: 'adfdes', checked: false, quantity:''}, {label: 'hghdgs', checked: false, quantity:''}, {label: 'srtnf', checked: false, quantity:''}, {label: 'xfthd', checked: false, quantity:''}, {label: 'sbnhrr', checked: false, quantity:''}, {label: 'sfghhh', checked: false, quantity:''}, {label: 'sssddrr', checked: false, quantity:''} ] } } setMediaDeliverable = (value, index) => { let currentState = this.getStateCopy(); currentState.mediaDeliverables[index] = value; this.setState(currentState); } getStateCopy = () => Object.assign({}, this.state); render() { return ( <div className="App"> <Form key="mainForm" mediaDeliverablesOptions={this.state.mediaDeliverables} setMediaDeliverable={this.setMediaDeliverable} /> </div> ); } } export default App;
Form.js
import React from 'react'; import { makeStyles, useTheme } from '@material-ui/core/styles'; import FormControl from '@material-ui/core/FormControl'; import FormLabel from '@material-ui/core/FormLabel'; import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Checkbox from '@material-ui/core/Checkbox'; import MediaDeliverablesCheckBox from './MediaDeliverablesCheckBox'; const useStyles = makeStyles(theme => ({ container: { display: 'inline-block', flexWrap: 'wrap', }, root: { display: 'inline-block', flexWrap: 'wrap', maxWidth: 600, textAlign: 'left', }, extendedIcon: { marginRight: theme.spacing(1), }, formControl: { margin: theme.spacing(1), minWidth: 120, maxWidth: 300, }, textField: { marginLeft: theme.spacing(1), marginRight: theme.spacing(1), width: 370, }, dense: { marginTop: 19, }, chips: { display: 'flex', flexWrap: 'wrap', }, chip: { margin: 2, }, noLabel: { marginTop: theme.spacing(3), }, })); const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { PaperProps: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }; function getStyles(name, accountName, theme) { // console.log('>> [form.js] (getStyles) ',accountName) return { fontWeight: accountName.indexOf(name) === -1 ? theme.typography.fontWeightRegular : theme.typography.fontWeightMedium, }; } export default function Form(props) { const mediaDeliverablesOptions = props.mediaDeliverablesOptions; const classes = useStyles(); const theme = useTheme(); const CheckboxGroup = ({ values, label, onChange }) => ( <FormControl component="fieldset"> <FormLabel component="legend">{label}</FormLabel> <FormGroup> {values.map((value, index) => ( <FormControlLabel key={index} control={ <Checkbox checked={value.checked} onChange={onChange(index)} /> } label={value.label} /> ))} </FormGroup> </FormControl> ); const MediaDeliverableCheckBoxList = ({values, label}) => ( <FormControl component="fieldset"> <FormLabel component="legend">{label}</FormLabel> <FormGroup> {values.map((value, index) => ( <MediaDeliverablesCheckBox key={index} mediaDeliverablesOptions={value} onMediaDeliverableChange={onMediaDeliverableChange(index)} /> ))} </FormGroup> </FormControl> ); const onCheckBoxChange = index => ({ target: { checked } }) => { const newValues = [...values]; const value = values[index]; newValues[index] = { ...value, checked }; props.setDesignOrDigital(newValues); }; const onMediaDeliverableChange = index => (deliverableData, e) => { props.setMediaDeliverable(deliverableData, index); } return ( <div className={classes.root}> <MediaDeliverableCheckBoxList label="Please Choose Deliverables:" values={mediaDeliverablesOptions} key="media-deliverable-checkbox-list" /> </div> ); }
MediaDeliverablesCheckbox.js
import React from 'react'; import Checkbox from '@material-ui/core/Checkbox'; import { makeStyles, useTheme } from '@material-ui/core/styles'; import FormControl from '@material-ui/core/FormControl'; import FormLabel from '@material-ui/core/FormLabel'; import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import TextField from '@material-ui/core/TextField'; export default function MediaDeliverablesCheckBox(props) { let deliverableData = Object.assign({}, props.mediaDeliverablesOptions); const onCheckBoxChange = (e) => { deliverableData.checked = e.target.checked; props.onMediaDeliverableChange(deliverableData, e); } const onQuantityChange = (e) => { deliverableData.quantity = e.target.value; props.onMediaDeliverableChange(deliverableData, e); } const CheckboxGroup = ({ value, label }) => ( <FormControl component="fieldset"> <FormGroup> <FormControlLabel control={ <Checkbox key={props.index} checked={value.checked} onChange={onCheckBoxChange} /> } label={label} /> </FormGroup> </FormControl> ); return( <div className="MediaDeliverablesCheckBox"> <CheckboxGroup key={props.index} label={props.mediaDeliverablesOptions.label} value={props.mediaDeliverablesOptions} /> <TextField key={'tf'+props.index} id={'quantity-'+props.index} label="Quantity" placeholder="How many do you need?" multiline variant="outlined" value={props.mediaDeliverablesOptions.quantity} onChange={onQuantityChange} fullWidth /> </div> ); }
根据Ryan C的建议编辑更新了Form.js。
import React from 'react'; import { makeStyles, useTheme } from '@material-ui/core/styles'; import FormControl from '@material-ui/core/FormControl'; import FormLabel from '@material-ui/core/FormLabel'; import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Checkbox from '@material-ui/core/Checkbox'; import MediaDeliverablesCheckBox from './MediaDeliverablesCheckBox'; const useStyles = makeStyles(theme => ({ container: { display: 'inline-block', flexWrap: 'wrap', }, root: { display: 'inline-block', flexWrap: 'wrap', maxWidth: 600, textAlign: 'left', }, extendedIcon: { marginRight: theme.spacing(1), }, formControl: { margin: theme.spacing(1), minWidth: 120, maxWidth: 300, }, textField: { marginLeft: theme.spacing(1), marginRight: theme.spacing(1), width: 370, }, dense: { marginTop: 19, }, chips: { display: 'flex', flexWrap: 'wrap', }, chip: { margin: 2, }, noLabel: { marginTop: theme.spacing(3), }, })); const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { PaperProps: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }; function getStyles(name, accountName, theme) { return { fontWeight: accountName.indexOf(name) === -1 ? theme.typography.fontWeightRegular : theme.typography.fontWeightMedium, }; } // Failed to compile // ./src/Form.js // Line 86: Parsing error: Unexpected token, expected "," // 84 | // 85 | const MediaDeliverableCheckBoxList = ({values, label, onMediaDeliverableChange}) => ( // > 86 | {values.map((value, index) => ( // | ^ // 87 | <MediaDeliverablesCheckBox // 88 | key={index} // 89 | index={index} // This error occurred during the build time and cannot be dismissed. const MediaDeliverableCheckBoxList = ({values, label, onMediaDeliverableChange}) => ( {values.map((value, index) => ( <MediaDeliverablesCheckBox key={index} index={index} mediaDeliverablesOptions={value} onMediaDeliverableChange={onMediaDeliverableChange(index)} /> ))} ); export default function Form(props) { const mediaDeliverablesOptions = props.mediaDeliverablesOptions; const classes = useStyles(); const theme = useTheme(); const CheckboxGroup = ({ values, label, onChange }) => ( <FormControl component="fieldset"> <FormLabel component="legend">{label}</FormLabel> <FormGroup> {values.map((value, index) => ( <FormControlLabel key={index} control={ <Checkbox checked={value.checked} onChange={onChange(index)} /> } label={value.label} /> ))} </FormGroup> </FormControl> ); const onCheckBoxChange = index => ({ target: { checked } }) => { const newValues = [...values]; const value = values[index]; newValues[index] = { ...value, checked }; props.setDesignOrDigital(newValues); }; const onMediaDeliverableChange = index => (deliverableData, e) => { props.setMediaDeliverable(deliverableData, index); } return ( <div className={classes.root}> <MediaDeliverableCheckBoxList onMediaDeliverableChange={onMediaDeliverableChange} /> </div> ); }
我看到两个主要问题:
您具有以下结构(省略了与我的观点不直接相关的详细信息):
export default function Form(props) { const onMediaDeliverableChange = index => (deliverableData, e) => { props.setMediaDeliverable(deliverableData, index); } const MediaDeliverableCheckBoxList = ({values, label}) => ( <FormGroup> {values.map((value, index) => ( <MediaDeliverablesCheckBox key={index} onMediaDeliverableChange={onMediaDeliverableChange(index)}/> ))} </FormGroup> ); return ( <MediaDeliverableCheckBoxList/> ); }
该函数MediaDeliverableCheckBoxList表示用于呈现<MediaDeliverableCheckBoxList/>元素的组件类型。每当Form由于道具或状态改变而重新渲染时,React都会重新渲染其子级。如果特定子项的组件类型相同(加上某些其他条件,例如,key如果指定则相同),则它将更新现有的DOM节点。如果特定子项的组件类型 不同 ,则将 删除 相应的DOM节点,并将新的DOM节点添加到DOM。
MediaDeliverableCheckBoxList
<MediaDeliverableCheckBoxList/>
Form
key
通过定义MediaDeliverableCheckBoxList组件类型 中 的Form功能,你是导致该组件类型为每个渲染不同。这将导致替换所有DOM节点,而不仅仅是更新它们,并且当删除之前具有焦点的DOM节点时,将导致焦点消失。这也将导致性能大大降低。
您可以通过以下方式解决此问题:将组件类型移到Form函数外部,然后添加所需的其他附加道具(例如onMediaDeliverableChange)来传达内的已知上下文Form。您还需要传递索引作为道具,MediaDeliverablesCheckBox因为它正在使用它。
onMediaDeliverableChange
MediaDeliverablesCheckBox
const MediaDeliverableCheckBoxList = ({values, label, onMediaDeliverableChange}) => ( <FormGroup> {values.map((value, index) => ( <MediaDeliverablesCheckBox key={index} index={index} onMediaDeliverableChange={onMediaDeliverableChange(index)}/> ))} </FormGroup> ); export default function Form(props) { const onMediaDeliverableChange = index => (deliverableData, e) => { props.setMediaDeliverable(deliverableData, index); } return ( <MediaDeliverableCheckBoxList onMediaDeliverableChange={onMediaDeliverableChange}/> ); }
您CheckboxGroup可能还有其他组件也遇到同样的问题。
CheckboxGroup