使用 React,在 StrictMode 中不推荐使用 findDOMNode 在使用 react-transition-group 时作为警告抛出
Using React, findDOMNode is deprecated in StrictMode is thrown as a warning when using react-transition-group
我正在使用包 react-transition-group,我已经尝试在 CSSTransition 组件上使用 nodeRef 道具,并在我的组件上添加了一个包装器,但我仍然收到有关 findDOMNode 的警告。
代码如下:
<CSSTransition
key={entry.id}
timeout={500}
classNames="timesheet-entry"
>
<TimesheetEntry
taskOptions={taskOptions || []}
deleteHandler={(event) => {
deleteHandler(event, entry.id.toString());
}}
data={entry}
dateChangeHandler={(date: Date) =>
dateChangeHandler(date, entry.id)
}
hoursChangeHandler={(event) => hoursChangeHandler(event, entry.id)}
taskCodeChangeHandler={(event, value) =>
taskCodeChangeHandler(event, value, entry.id)
}
/>
</CSSTransition>
TimesheetEntry 组件的代码:
function TimesheetEntry(props: TimesheetEntryProps) {
return (
<div>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
label="Date"
style={{ marginRight: '15px', height: '20px', marginTop: '-2px' }}
disableToolbar
variant="inline"
format="MM/dd/yyyy"
margin="normal"
value={props.data.date}
onChange={props.dateChangeHandler}
size="small"
KeyboardButtonProps={{
'aria-label': 'change date',
}}
/>
</MuiPickersUtilsProvider>
<Autocomplete
size="small"
style={{
width: 300,
display: 'inline-block',
marginRight: '15px',
}}
options={props.taskOptions}
getOptionLabel={(option) => option.name}
getOptionSelected={(option, value) => {
return option.id === value.id && option.name === value.name;
}}
onChange={props.taskCodeChangeHandler}
renderInput={(params) => (
<TextField {...params} label="Task" variant="outlined" />
)}
/>
<TextField
size="small"
style={{ marginRight: '15px', height: '20px' }}
label="Hours"
type="number"
inputProps={{ min: 0.5, step: 0.5 }}
onChange={props.hoursChangeHandler}
InputLabelProps={{
shrink: true,
}}
/>
<Button
style={{ marginRight: '15px' }}
variant="contained"
color="secondary"
size="small"
startIcon={<DeleteIcon />}
onClick={props.deleteHandler}
>
Delete
</Button>
</div>
);
}
export default TimesheetEntry;
我也在 codesandbox 中做了一些类似的代码设置 here
我已经尝试通过我的 TimesheetEntry 组件上的 div 包装器添加 nodeRef 和 ref 引用,但这似乎使动画表现不正常(添加新条目可以正常工作,但是当我尝试删除条目时,动画似乎不再起作用了)。我也在寻找一种无需在 TimesheetEntry 组件上创建 div 包装器的方法。
在您的 CodeSandbox 演示中实际上有两个不同的 findDOMNode
警告:
当您第一次添加或删除条目时,这源于直接使用 react-transition-group
for TimesheetEntry
。
当您保存时间表时,它源自 间接 使用 react-transition-group
到 Material UI' s Snackbar
组件。
不幸的是,你无法控制后者,所以让我们修复前者;您正在管理一个过渡 TimesheetEntry
组件列表,但要正确实现 nodeRef
,每个元素都需要一个不同的 ref 对象,并且因为您不能在循环中调用 React 挂钩(请参阅 rules of hooks ), 你必须创建一个单独的组件:
const EntryContainer = ({ children, ...props }) => {
const nodeRef = React.useRef(null);
return (
<CSSTransition
nodeRef={nodeRef}
timeout={500}
classNames="timesheet-entry"
{...props}
>
<div ref={nodeRef}>
{children}
</div>
</CSSTransition>
);
};
你将围绕 TimesheetEntry
:
const controls: JSX.Element[] = entries.map((entry: entry, index: number) => {
return (
<EntryContainer key={entry.id}>
<TimesheetEntry
deleteHandler={event => {
deleteHandler(event, entry.id.toString());
}}
data={entry}
dateChangeHandler={(date: Date) => dateChangeHandler(date, entry.id)}
hoursChangeHandler={event => hoursChangeHandler(event, entry.id)}
taskCodeChangeHandler={(event, value) =>
taskCodeChangeHandler(event, value, entry.id)
}
/>
</EntryContainer>
);
});
你说你已经尝试过类似的东西,但我怀疑你忘记转发 EntryContainer
的道具给 CSSTransition
,这是关键的一步,因为这些正在被传递通过 TransitionGroup
.
我的回答使用与@sivenon 的回答相同的策略,但是在使用您的 Transition 的组件中编写占用 space 的“无用”引用很烦人。所以这里有一个包装器,可以在不使用隐藏 div 的情况下为您添加引用,因为额外的标记会破坏样式。
import React, { useRef } from 'react';
import { CSSTransition as _CSSTransition } from 'react-transition-group';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
const CSSTransition = (props: CSSTransitionProps) => {
const nodeRef = useRef(null);
return (
<_CSSTransition {...props} nodeRef={nodeRef}>
<>
{React.Children.map(props.children, (child) => {
// @ts-ignore
return React.cloneElement(child, { ref: nodeRef });
})}
</>
</_CSSTransition>
);
};
export default CSSTransition;
Caleb Taylor's 通过转发 ref 来解决问题,如果在克隆之前测试子元素的有效性,则可以避免使用 // @ts-ignore
。例如,
import { Children, cloneElement, isValidElement, useRef } from 'react';
import { CSSTransition as _CSSTransition } from 'react-transition-group';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
export const CSSTransition = ({ children, ...props }: CSSTransitionProps) => {
const nodeRef = useRef(null);
return (
<_CSSTransition {...props} nodeRef={nodeRef}>
<>
{Children.map(children, child =>
isValidElement(child)
? cloneElement(child, { ref: nodeRef })
: child
)}
</>
</_CSSTransition>
);
};
这个想法来自 一个不相关的问题。
我正在使用包 react-transition-group,我已经尝试在 CSSTransition 组件上使用 nodeRef 道具,并在我的组件上添加了一个包装器,但我仍然收到有关 findDOMNode 的警告。
代码如下:
<CSSTransition
key={entry.id}
timeout={500}
classNames="timesheet-entry"
>
<TimesheetEntry
taskOptions={taskOptions || []}
deleteHandler={(event) => {
deleteHandler(event, entry.id.toString());
}}
data={entry}
dateChangeHandler={(date: Date) =>
dateChangeHandler(date, entry.id)
}
hoursChangeHandler={(event) => hoursChangeHandler(event, entry.id)}
taskCodeChangeHandler={(event, value) =>
taskCodeChangeHandler(event, value, entry.id)
}
/>
</CSSTransition>
TimesheetEntry 组件的代码:
function TimesheetEntry(props: TimesheetEntryProps) {
return (
<div>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
label="Date"
style={{ marginRight: '15px', height: '20px', marginTop: '-2px' }}
disableToolbar
variant="inline"
format="MM/dd/yyyy"
margin="normal"
value={props.data.date}
onChange={props.dateChangeHandler}
size="small"
KeyboardButtonProps={{
'aria-label': 'change date',
}}
/>
</MuiPickersUtilsProvider>
<Autocomplete
size="small"
style={{
width: 300,
display: 'inline-block',
marginRight: '15px',
}}
options={props.taskOptions}
getOptionLabel={(option) => option.name}
getOptionSelected={(option, value) => {
return option.id === value.id && option.name === value.name;
}}
onChange={props.taskCodeChangeHandler}
renderInput={(params) => (
<TextField {...params} label="Task" variant="outlined" />
)}
/>
<TextField
size="small"
style={{ marginRight: '15px', height: '20px' }}
label="Hours"
type="number"
inputProps={{ min: 0.5, step: 0.5 }}
onChange={props.hoursChangeHandler}
InputLabelProps={{
shrink: true,
}}
/>
<Button
style={{ marginRight: '15px' }}
variant="contained"
color="secondary"
size="small"
startIcon={<DeleteIcon />}
onClick={props.deleteHandler}
>
Delete
</Button>
</div>
);
}
export default TimesheetEntry;
我也在 codesandbox 中做了一些类似的代码设置 here
我已经尝试通过我的 TimesheetEntry 组件上的 div 包装器添加 nodeRef 和 ref 引用,但这似乎使动画表现不正常(添加新条目可以正常工作,但是当我尝试删除条目时,动画似乎不再起作用了)。我也在寻找一种无需在 TimesheetEntry 组件上创建 div 包装器的方法。
在您的 CodeSandbox 演示中实际上有两个不同的 findDOMNode
警告:
当您第一次添加或删除条目时,这源于直接使用
react-transition-group
forTimesheetEntry
。当您保存时间表时,它源自 间接 使用
react-transition-group
到 Material UI' sSnackbar
组件。
不幸的是,你无法控制后者,所以让我们修复前者;您正在管理一个过渡 TimesheetEntry
组件列表,但要正确实现 nodeRef
,每个元素都需要一个不同的 ref 对象,并且因为您不能在循环中调用 React 挂钩(请参阅 rules of hooks ), 你必须创建一个单独的组件:
const EntryContainer = ({ children, ...props }) => {
const nodeRef = React.useRef(null);
return (
<CSSTransition
nodeRef={nodeRef}
timeout={500}
classNames="timesheet-entry"
{...props}
>
<div ref={nodeRef}>
{children}
</div>
</CSSTransition>
);
};
你将围绕 TimesheetEntry
:
const controls: JSX.Element[] = entries.map((entry: entry, index: number) => {
return (
<EntryContainer key={entry.id}>
<TimesheetEntry
deleteHandler={event => {
deleteHandler(event, entry.id.toString());
}}
data={entry}
dateChangeHandler={(date: Date) => dateChangeHandler(date, entry.id)}
hoursChangeHandler={event => hoursChangeHandler(event, entry.id)}
taskCodeChangeHandler={(event, value) =>
taskCodeChangeHandler(event, value, entry.id)
}
/>
</EntryContainer>
);
});
你说你已经尝试过类似的东西,但我怀疑你忘记转发 EntryContainer
的道具给 CSSTransition
,这是关键的一步,因为这些正在被传递通过 TransitionGroup
.
我的回答使用与@sivenon 的回答相同的策略,但是在使用您的 Transition 的组件中编写占用 space 的“无用”引用很烦人。所以这里有一个包装器,可以在不使用隐藏 div 的情况下为您添加引用,因为额外的标记会破坏样式。
import React, { useRef } from 'react';
import { CSSTransition as _CSSTransition } from 'react-transition-group';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
const CSSTransition = (props: CSSTransitionProps) => {
const nodeRef = useRef(null);
return (
<_CSSTransition {...props} nodeRef={nodeRef}>
<>
{React.Children.map(props.children, (child) => {
// @ts-ignore
return React.cloneElement(child, { ref: nodeRef });
})}
</>
</_CSSTransition>
);
};
export default CSSTransition;
Caleb Taylor's // @ts-ignore
。例如,
import { Children, cloneElement, isValidElement, useRef } from 'react';
import { CSSTransition as _CSSTransition } from 'react-transition-group';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
export const CSSTransition = ({ children, ...props }: CSSTransitionProps) => {
const nodeRef = useRef(null);
return (
<_CSSTransition {...props} nodeRef={nodeRef}>
<>
{Children.map(children, child =>
isValidElement(child)
? cloneElement(child, { ref: nodeRef })
: child
)}
</>
</_CSSTransition>
);
};
这个想法来自