我的 React Native 项目中有一个状态变量。当调用特定函数时需要更新它。然而,
setState
方法是异步的,导致我的变量在应该更新之后被更新。
我需要发生的是:
发生的事情是:
setState
;为了说明这是如何管理的,这就是我的代码:
const MyComponent: FC<MyComponentProps> = ({/*my component props*/}) => {
const [rows, setRows] = useState<Array<boolean>>([]);
useEffect(() => {
console.log('rows on useEffect: ', rows);
}, [rows]);
async function OnFocus(): Promise<void> {
await GetApplication();
}
async function GetApplication(): Promise<void> {
const _state: ApplicationParameters = await ctrl.getApplicationParameters(
ctrl.ctrl.getDevice()
);
console.log('_state.rows: ', _state.rows);
console.log('rows before setRows()', rows);
setRows(_state.rows!);
console.log('rows after setRows()', rows);
}
return(
<RowBars theme={theme} rows={rows} />
)
}
上述代码的日志显示:
LOG _state.rows: [true, true, true, true, true, true, true, true, true, true, true]
LOG rows before setRows() []
LOG rows after setRows() []
LOG rows on useEffect() [true, true, true, true, true, true, true, true, true, true, true]
LOG rows on useEffect() [true, true, true, true, true, true, true, true, true, true, true]
如果稍后触发状态更新,数组会显示已满,但不会构建任何内容。
我的变量后面用到的组件如下:
interface RowBarsProps {
theme: AppColors;
rows: Array<boolean>;
}
export const RowBars: FC<RowBarsProps> = ({ theme, rows }: RowBarsProps) => {
const [Rows] = useState<number>(rows.length);
const _rows = [];
for (let i = 0; i < Rows; i++) {
_rows.push(<RowBar theme={theme} isOn={rows[i]} />);
}
return <RowToRowLiteBars>{_rows}</RowToRowLiteBars>;
};
我尝试过:
rows
上更新useEffect
。但是,我没有可靠的变量来观察 useEffect
;rows
更新时,props 变量尚未更新,所以它会尝试从未定义的值设置 rows
。仔细查看我的代码,我发现问题出在子组件上。发生的事情是,它并不是为了感知父组件中的变化而构建的。
我所做的是创建一个
useEffect()
来观察即将到来的rows
的变化。
不知道这是否是最佳实践,但它确实有效。
export const RowBars: FC<RowBarsProps> = ({ theme, rows }: RowBarsProps) => {
const [rowBars, setRowBars] = useState<RowBarsState>([]);
// Updates the row bars according to `rows` current state
useEffect(() => {
setRowBars(() => {
const newRowBars = rows.map((row) => <RowBar theme={theme} isOn={row} />);
return newRowBars;
});
}, [rows, theme]);
return <RowToRowLiteBars>{rowBars}</RowToRowLiteBars>;
};