Не выводится выбранное значение в выпадающем списке после изменения других полей
Есть форма, в нее передаю данные с другой страницы, принимаю и перезаписываю в переменные useState для дальнейшего изменения. Выпадающий список для подобъекта формируется через запрос с выборкой по полю subobject. Выпадающий список для системы формируется, если выбран подобъект, иначе пустой список, при перевыборе подобъекта на другой, значение системы очищается.
Проблема заключается в том, что в выпадающих списках не выводится значение, которое пришло с другой страницы.
При выборе значений в выпадающих поля функционал работает почти исправно - если в подобъекте выбрано поле, которое пришло до этого не формируется список для системы, если выбрано другое - то список формируется. При ручном выборе значения выводятся в текстовое поле, но значение слетает с текстового поля после изменения других полей на форме, например, содержания замечания - однако в переменных в логах выводит выбранное значение до этого.
Подскажите, с чем это может быть связано и как следует решить проблему.
экранная форма
import React, { useState, useEffect } from 'react';
import { Text, View, TextInput, ScrollView} from 'react-native';
import {useLocalSearchParams } from 'expo-router';
import ListOfSystem from '@/components/ListOfSystem';
import { Structure } from '../(tabs)/structure';
import ListOfSubobj from '@/components/ListOfSubobj';
export type ListToDrop = {
label: string;
value: string;
};
export default function CreateNote() {
const [array, setArray] = useState<Structure[]>([]);//данные получаю при вызове запроса
const listSubObj = [];//список подобъектов из структуры
const [noteListSubobj, setNoteListSubobj] = useState<boolean>(true);//ограничение на получение листа подобъектов только единожды
const listSystem = [];//список систем из структуры на соответствующий выбранный подобъект
const [noteListSystem, setNoteListSystem] = useState<boolean>(false);//ограничение на отправку листа систем в компонент
const [statusReq, setStatusReq] = useState(false);//для выпадающих списков, передача данных, когда True
const [subObject, setSubObject] = useState('');
const [systemName, setSystemName] = useState(' ');
const [description, setDescription] = useState('');
const [execut, setExecut] = useState('');
const [bufsubobj, setBufsubobj] = useState('');
const [bufsystem, setBufsystem] = useState('');
const {subObject} = useLocalSearchParams();//получение подобъекта
//далее получаю все данные по форме и с помощью useState записываю в переменные
const TwoFunction = () => {
if(systemName != bufsystem){
setBufsystem(systemName);
if (systemName != ' ' ){
const filtered = array.filter(item => item.subObjectName === subObject);
const filteredS = filtered[0].data.filter(item => item.systemName === systemName);
if(filteredS.length != 0){
setExecut(filteredS[0].ciwexecutor);
}
else{
setExecut('');
setSystemName(' ');
}
setNoteListSystem(false);
}
}
};
useEffect(() => {
//формирование выпадающего списка для подобъекта
if(statusReq && noteListSubobj){//вызов происходит только один раз
setNoteListSubobj(false);
const buf = array.map(item => ({label: item.subObjectName, value: item.subObjectName}));
listSubObj.push(...buf);
}
//формирование выпадающего списка для системы после того как выбран подобъект
if (subObject ){
const filtered = array.filter(item => item.subObjectName === subObject);
console.log(filtered[0].data);
for (const pnrsystemId in filtered[0].data) {
const buf = filtered.map(item => ({label: item.data[pnrsystemId].systemName, value: item.data[pnrsystemId].systemName}));
console.log('listSystem',buf);
listSystem.push(...buf);
}
if(subObject != bufsubobj){ //это работает, но после каждого обновления subObject в systemName попадает с кеша(?) последнее значение
setSystemName('');
setExecut('');
setBufsubobj(subObject);
}
}
if (execut){
submitData();
}
}, [statusReq, noteListSubobj, subObject, systemName, execut]);
const submitData = async () => {
//запрос на запись данных в бд
}
return (
<View >
<View >
<Text >Подобъект</Text>
<ListOfSubobj post = {subObject} list={listSubObj} statusreq={statusReq} onChange = {(subObj) => setSubObject(subObj)}/>
</View>
<Text >Система</Text>
<ListOfSystem post = {systemName} subobj={subObject} list={listSystem} statusreq={noteListSystem} onChange = {(subObj) => setSystemName(subObj)}/>
<Text >Содержание замечания</Text>
<TextInput
placeholderTextColor="#111"
onChangeText={setDescription}
value={description}
/>
<CustomButton title="Добавить замечание" handlePress={TwoFunction} />
</View>
);
}
ListOfSubobj
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import { Dropdown } from 'react-native-element-dropdown';
export type ListToDrop = {
label: string;
value: string;
};
type Props = {
list: ListToDrop[];//список
post: string;//значение из бд статуса для просмотра, при записи передавать пустую строку
statusreq: boolean;//для обновления значения даты при получении даты с запроса
onChange: (subobj: string, ) => void; // Функция для обновления значения
};
const ListOfSubobj = ({list, post, statusreq, onChange }: Props) => {
const [value, setValue] = useState<string >();
const [data, setData] = useState<ListToDrop[]>([]);
const [isFocus, setIsFocus] = useState(false);
const [startD, setStartD] = useState<boolean>(true);//при первом рендеринге поставить значения из бд
const fontScale = useWindowDimensions().fontScale;
const ts = (fontSize: number) => {
return (fontSize / fontScale)};
if (statusreq && startD){//запись при первом и единственном рендеринге
setValue(post);//значение из БД
setStartD(false);
setData(list);
}
if (value){
onChange(value);
}
return (
<View >
<Dropdown
data={data}
search
maxHeight={300}
itemTextStyle={{fontSize: ts(14)}}
labelField="label"
valueField="value"
placeholder={!isFocus ? 'Не выбрано' : 'Не выбрано'}
searchPlaceholder="Search..."
value={value}
onFocus={() => setIsFocus(true)}
onBlur={() => setIsFocus(false)}
onChange={item => {
setValue(item.value);
setIsFocus(false);
}}
/>
</View>
);
};
export default ListOfSubobj;
ListOfSystem
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import { Dropdown } from 'react-native-element-dropdown';
export type ListToDrop = {
label: string;
value: string;
};
type Props = {
list: ListToDrop[];//список
post: string;//значение из бд статуса для просмотра, при записи передавать пустую строку
onChange: (subobj: string, ) => void; // Функция для обновления значения
};
const ListOfSystem = ({list, post, onChange}: Props) => {
const [value, setValue] = useState<string >();
const [data, setData] = useState<ListToDrop[]>([]);
const [isFocus, setIsFocus] = useState(false);
useEffect(
() => {
if(list){
setValue(post);
setData(list);
}
if(post != ' '){
setValue(post);
//setData(list);
console.log('post List', list );
}
}, [ list]
)
if (value){
onChange(value);
}
return (
<View >
<Dropdown
data={data}
search
maxHeight={300}
labelField="label"
valueField="value"
placeholder={!isFocus ? 'Не выбрано' : 'Не выбрано'}
searchPlaceholder="Search..."
value={value}
onFocus={() => setIsFocus(true)}
onBlur={() => setIsFocus(false)}
onChange={item => {
setValue(item.value);
setIsFocus(false);
}}
/>
</View>
);
};
export default ListOfSystem;
Ответы (1 шт):
У тебя несколько проблем в коде, которые могут вызывать этот баг. Давай разбираться.
- Состояние value в Dropdown не обновляется правильно В ListOfSubobj и ListOfSystem у тебя используется useState(value), но когда post обновляется (новое значение приходит с другой страницы), value остается старым. Как исправить: Добавь useEffect, который будет следить за post и обновлять value:
useEffect(() => {
setValue(post);
}, [post]);
- Перезапись value внутри if (value)
if (value){
onChange(value);
}
Этот код в ListOfSubobj и ListOfSystem вызовет onChange() при каждом ререндере, даже если пользователь ничего не выбирал. Это может приводить к зацикливанию. Исправь на:
useEffect(() => {
if (value) {
onChange(value);
}
}, [value]);
- Передача list как пустого массива
listSystem.push(...buf);
У тебя listSystem — это просто пустой массив, объявленный в CreateNote. Но ListOfSystem использует этот массив как пропс list={listSystem}. Это значит, что в Dropdown список систем может не обновляться. Как исправить: Вместо listSystem используй useState:
const [listSystem, setListSystem] = useState<ListToDrop[]>([]);
Затем обновляй listSystem внутри useEffect:
useEffect(() => {
if (subObject) {
const filtered = array.filter(item => item.subObjectName === subObject);
const newList = filtered.map(item => ({
label: item.systemName,
value: item.systemName
}));
setListSystem(newList);
}
}, [subObject]);
- Очистка systemName при изменении subObject У тебя есть этот код:
if(subObject != bufsubobj){
setSystemName('');
setExecut('');
setBufsubobj(subObject);
}
Однако systemName очищается, но в ListOfSystem useEffect не всегда это видит. Как исправить: Вместо '' лучше установить undefined, так как Dropdown может некорректно работать с пустыми строками:
setSystemName(undefined);
- Передача post в Dropdown В ListOfSystem и ListOfSubobj у тебя post не передается корректно, так как value не синхронизируется. Исправь:
<ListOfSystem
post={systemName}
subobj={subObject}
list={listSystem}
statusreq={noteListSystem}
onChange={(value) => setSystemName(value)}
/>
Теперь systemName всегда будет совпадать с post.
Попробуй эти изменения, и выпадающие списки должны начать правильно отображать переданное значение!