Issue
I have a state variable in my React Native Project. It needs to be updated when a specific function is called. However, the setState
method being asyncronous results in my variable being updated after it should.
What I need to happen is:
- The screen starts with said variable as an empty array;
- When the screen is focused, it fills the array, and creates components on screen according to the array;
What is happening is:
- The screen starts with said variable as an empty array;
- When the screen is focused, I try to fill the array using
setState
; - When trying to create the components, because the array is empty, nothing happens;
- The array is filled after the page is already built.
To illustratehow this is being managed, this is what my code looks like:
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} />
)
}
The log for the above code shows:
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]
If something triggers the state to update later, the array appears filled, but nothing is built.
The component where my variable is later used is as follows:
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>;
};
I tried:
- Updating
rows
onuseEffect
. However, I don't have a reliable variable to watch on the dependency array ofuseEffect
; - Initializing rows from an inherited props variable. However, because when
rows
is updated the props variable hasn't been yet updated, it tries to setrows
from an undefined value.
Solution
Looking closely on my code I found out that the problem was on the child component. What was happening was that it wasn't built for perceiving the changes in the parent component.
What I did was to create a useEffect()
to watch for changes in the coming rows
.
Don't know if it is the best practice, but it worked pretty well.
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>;
};
Answered By - Homero Kemmerich
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.