Javascript 在子挂载上设置父状态是否为反模式?
我正在使用React创建一个表单,并创建了一个Javascript 在子挂载上设置父状态是否为反模式?,javascript,reactjs,Javascript,Reactjs,我正在使用React创建一个表单,并创建了一个组件,该组件需要根据特定类型的子元素数量呈现不同的包装器元素 例如,如果字段包装单个输入,它应该呈现一个包装器和一个。但是,如果它包装多个输入,则应呈现一个和一个 至关重要的是,子项不一定是组件的直接后代,因此使用React.children.count计算子项将不起作用 我可以通过在装入子输入时设置父字段状态轻松完成此操作,例如: const FormFieldContext = createContext({}); // Simplified
组件,该组件需要根据特定类型的子元素数量呈现不同的包装器元素
例如,如果字段包装单个输入,它应该呈现一个包装器
和一个
。但是,如果它包装多个输入,则应呈现一个
和一个
至关重要的是,子项不一定是
组件的直接后代,因此使用React.children.count计算子项
将不起作用
我可以通过在装入子输入时设置父字段状态轻松完成此操作,例如:
const FormFieldContext = createContext({});
// Simplified Field component
const Field = ({ label, children, ...props }) => {
const [fieldCount, setFieldCount] = useState(0);
const Wrapper = fieldCount > 1 ? 'fieldset' : 'div';
const Label = fieldCount > 1 ? 'legend' : 'label';
return (
<Wrapper>
<Label>{label}</Label>
<FormFieldContext.Provider value={{ setFieldCount }}>
{children}
</FormFieldContext.Provider>
</Wrapper>
);
};
// Inside <Checkbox />
const Checkbox = ({ name, ...props }) => {
const { setFieldCount } = useContext(FormFieldContext);
useLayoutEffect(() => {
setFieldCount(count => count + 1);
return () => {
setFieldCount(count => count - 1);
};
}, [setFieldCount, name]);
return ( /** etc */ );
};
输入您的电子邮件
选择你的金属
青铜色
银币
实际上,可以递归地从子项
道具中获取React组件树中的所有子项,当您拥有所有子项时,您可以计算出类型为复选框
等的组件的数量,以确定应如何包装子项
可能有更优雅的方法,但在下面的代码示例中,我使用递归地
将直接子级减少为包含所有子级的平坦数组
const getChildrenRecursively = (soFar, parent) => {
if(typeof parent === "string") return soFar.concat(parent);
const children = Array.isArray(parent.props.children) ?
parent.props.children :
React.Children.toArray(parent.props.children);
const childCount = children.length;
if(childCount <= 0) {
return soFar.concat(parent);
} else {
return soFar.concat([parent], children.flatMap(child => getChildrenRecursively([], child)));
}
}
它确实“感觉”有点像反模式,并将表单和字段组件连接在一起。我会为Fieldset变体创建一个单独的组件。谢谢你的建议。我没有想到你可以递归地得到孩子——这绝对是一种选择。
const getChildrenRecursively = (soFar, parent) => {
if(typeof parent === "string") return soFar.concat(parent);
const children = Array.isArray(parent.props.children) ?
parent.props.children :
React.Children.toArray(parent.props.children);
const childCount = children.length;
if(childCount <= 0) {
return soFar.concat(parent);
} else {
return soFar.concat([parent], children.flatMap(child => getChildrenRecursively([], child)));
}
}