在使用React Native开发适用于Android的应用程序时,我偶然发现了一个奇怪的问题。
有一个SearchBar可以在数据库上执行名称搜索。结果应该被渲染。在下面的代码中,您看到使用useEffect()
在外部定义变量后,我在useRef()
-Hook中设置了变量:let returnValue = useRef('No results');
因此,我希望如果键入一个名称(例如“ Mike”),则数据库结果(存储在returnValue.current
中)将在提交后立即呈现。
但是没有。
实际上,当我再次打开搜索栏并删除最后一个字符并保留“ Mik”后,将呈现结果“ Mike”。然后,应用程序呈现“ Mike”,就好像它只落后了一步。
在搜索问题之后,我刚刚发现与useState()
-Hook异步,但没有与useEffect()
异步的“问题”。当我执行console.log()
useState()
时,一切设置正确。即使在useEffect()
内-记录returnValue.current
也总是在正确的时间给出正确的结果。一个单一的问题是returnValue.current
的渲染具有这种奇怪的延迟。
有人能够揭露这种行为的神秘色彩吗?
import ...
const SearchBar = props => {
let [inputValue, setInputValue] = useState(null);
let returnValue = useRef('No results');
const sendInputValueToReduxStore = text => {
setInputValue(text);
props.setInputValueSearchBar(text);
};
useEffect(() => {
// setting database schema
const personsSchema = {
name: 'realm',
properties: {
name: 'string?',
color: 'string?',
},
};
// open the database
let database = new Realm({
path: fs.DocumentDirectoryPath + '/default.realm',
schema: [personsSchema ],
readOnly: true,
});
// doing the database query
const allPersons = database.objects('realm');
let resultArray = [];
const query = inputValue;
const queryResult = inputValue
? allPersons.filtered("name == '" + query + "'")
: 'default';
resultArray = Array.from(queryResult);
const personNamesArray = resultArray.map(value => value.name);
const personNames = personNamesArray.toString();
returnValue.current = personNames;
// logging always correct
console.log('person name: ', personNames);
}, [inputValue]);
const isText = props.text;
return (
<View>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input
placeholder="Search"
onChangeText={text => sendInputValueToReduxStore(text)}
value={inputValue}
/>
</Item>
</Header>
{isText && (
<View>
<Text>{props.text}</Text>
</View>
)}
//returnValue.current is rendered with delay
{returnValue && <Text>{returnValue.current}</Text>}
</View>
);
};
答案 0 :(得分:1)
尝试仅用useRef
钩替换useState
钩。由于returnValue
只是从inputValue
得出的计算值,就足够了:
import ...
const SearchBar = props => {
let [inputValue, setInputValue] = useState(null);
let [returnValue, setReturnValue] = useState(null);
const sendInputValueToReduxStore = text => {
setInputValue(text);
props.setInputValueSearchBar(text);
};
useEffect(() => {
// setting database schema
const personsSchema = {
name: 'realm',
properties: {
name: 'string?',
color: 'string?',
},
};
// open the database
let database = new Realm({
path: fs.DocumentDirectoryPath + '/default.realm',
schema: [personsSchema ],
readOnly: true,
});
// doing the database query
const allPersons = database.objects('realm');
let resultArray = [];
const query = inputValue;
const queryResult = inputValue
? allPersons.filtered("name == '" + query + "'")
: 'default';
resultArray = Array.from(queryResult);
const personNamesArray = resultArray.map(value => value.name);
const personNames = personNamesArray.toString();
setReturnValue(personNames);
}, [inputValue]);
const isText = props.text;
return (
<View>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input
placeholder="Search"
onChangeText={text => sendInputValueToReduxStore(text)}
value={inputValue}
/>
</Item>
</Header>
{isText && (
<View>
<Text>{props.text}</Text>
</View>
)}
{returnValue && <Text>{returnValue}</Text>}
</View>
);
};