我编写了一个组件,该组件应该列出一堆带有相应文本字段的复选框。当您单击复选框时,或在字段中输入内容是为了更新状态。
该文本框可以正常工作,但是当我在字段中键入内容时,它会更新状态为ok,但是每当我敲击键盘时,我都会失去焦点。
我意识到这可能是由于没有设置键,所以我为所有内容添加了键,但是仍然失去了重点。有一次我尝试在事件中添加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>
);
}
答案 0 :(得分:1)
我看到两个主要问题:
您具有以下结构(省略了与我的观点不直接相关的详细信息):
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
函数中的内部中定义Form
组件类型,您将导致该组件类型在每个渲染器上都不同。这将导致替换所有DOM节点,而不仅仅是更新它们,并且当删除之前具有焦点的DOM节点时,将导致焦点消失。这也会导致性能大大降低。
您可以通过以下方式解决此问题:将组件类型移至Form
函数之外,然后添加所需的其他附加道具(例如onMediaDeliverableChange
)以传达Form
内部已知的上下文。您还需要将索引作为道具传递给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
以及其他组件上也遇到了同样的问题。
答案 1 :(得分:0)
此问题仅是由于您key
中的TextField
。您必须确保密钥在每次更新时均保持不变。否则,您将面对当前的问题。