reactjs - Do I really need the Hook useEffect() here?
问题描述
As a React Native newbie, I am working on an application for android. Basically, the app enables the user to filter a database according to specific search parameters.
Now I tried to convert a Class Component into a Functional component. The component just loads a prepopulated (Realm-) database, displays a search bar waiting for user input, performs a database query according to the user's input and shows the result.
In the "old" version, database setup was done during componentDidMount()
, now I thought using the useEffect()
Hook will do the job, since it works as a replacement for componentDidMount()
. But I found that doing all the logic (which I actually wanted to put into the Hook) "naked" without any Hook works just fine.
I am so confused because of this behavior since I didn't expect that it would work this way. Surely I missed something. Googling unfortunately didn't give answers. Can you help me? Below is the code of the component I am talking of, SearchBar.js
Thanks a lot for your help!
import React, {useState} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {connect} from 'react-redux';
import {Header, Icon, Item, Input} from 'native-base';
import Realm from 'realm';
import fs from 'react-native-fs';
import {setInputValueSearchBar} from '../../../actions';
const SearchBar = props => {
let [inputValue, setInputValue] = useState(null);
const sendInputValueToReduxStore = text => {
setInputValue(text);
props.setInputValueSearchBar(text);
};
// from here on, I wanted to use useEffect() ...
const dogsSchema = {
name: 'realm',
properties: {
name: 'string?',
color: 'string?',
},
};
let realm = new Realm({
path: fs.DocumentDirectoryPath + '/default.realm',
schema: [dogsSchema],
readOnly: true,
});
const dogs = realm.objects('realm');
let resultArray = [];
const databaseRequest = () => {
const query = inputValue;
const result = inputValue
? dogs.filtered("name == '" + query + "'")
: 'default';
resultArray = Array.from(result);
return resultArray.map(dog => (
<Text className="dog" key={dog.name}>
{dog.name}
</Text>
));
};
//... until here
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>
<View>{databaseRequest()}</View>
</View>
);
};
function mapStateToProps(state) {
return {
inputValue: state.inputValue,
};
}
const mapDispatchToProps = {
setInputValueSearchBar,
};
export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);
This is the same component as Class Component before refactoring:
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {connect} from 'react-redux';
import {Header, Icon, Item, Input} from 'native-base';
import Realm from 'realm';
import fs from 'react-native-fs';
import {setInputValueSearchBar} from '../../../actions';
class SearchBar extends React.Component {
state = {
inputValue: null,
};
sendInputValueToReduxStore(text) {
this.setState({inputValue: text});
this.props.setInputValueSearchBar(text);
}
componentWillMount() {
const dogsSchema = {
name: 'realm',
properties: {
name: 'string?',
color: 'string?',
},
};
let realm = new Realm({
path: fs.DocumentDirectoryPath + '/default.realm',
schema: [dogsSchema],
readOnly: true,
});
const dogs = realm.objects('realm');
let resultArray = [];
this.databaseRequest = () => {
const query = this.state.inputValue;
const result = this.state.inputValue
? dogs.filtered("name == '" + query + "'")
: 'default';
resultArray = Array.from(result);
return resultArray.map(dog => (
<Text className="dog" key={dog.name}>
{dog.name}
</Text>
));
};
}
render() {
const isText = this.props.text;
return (
<View>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input
placeholder="Search"
onChangeText={text => this.sendInputValueToReduxStore(text)}
value={this.state.inputValue}
/>
</Item>
</Header>
{isText && (
<View>
<Text>{this.props.text}</Text>
</View>
)}
<View>{this.databaseRequest()}</View>
</View>
);
}
}
function mapStateToProps(state) {
return {
inputValue: state.inputValue,
};
}
const mapDispatchToProps = {
setInputValueSearchBar,
};
export default withNavigation(
connect(mapStateToProps, mapDispatchToProps)(SearchBar),
);
解决方案
当然,没有useEffect
. 但是每次重新渲染组件时也会发生这种情况。这在您的应用程序中可能不是问题,原因如下:
- 也许您的组件不会经常重新渲染,具体取决于您正在管理/更新的状态以及位置
- 也许逻辑是微不足道的资源消耗,如果经常执行也没关系
但如果不是这些情况,您可能需要衡量并确认正在发生的事情。在此处将一些日志记录输出添加到您的设置逻辑中,并在日志中观察它被调用的频率。
如果它没有被不断地重新调用(或者至少不是不合理的频繁),那么你当然可以保持这样的状态。请注意,它可能会根据该组件之外的因素不断地重新调用,任何会导致该组件重新渲染的因素。
如果它不断地被重新调用,那么这就是useEffect
目的。您可以仅在第一次加载组件时执行此逻辑,因为没有依赖项:
useEffect(() => {
// your logic
}, []);
或者,您可以添加依赖项以在这些依赖项更改时触发执行此逻辑。例如,可能会在您进行inputValue
更改时重新调用它:
useEffect(() => {
// your logic
}, [inputValue]);
推荐阅读
- google-chrome - 由于 Chrome 85 cache.addAll of Service Worker 不使用 Cache-Control 缓存到“no-store”
- c# - asp.net core 3.1 EF ConcurrencyCheck不能使用剃须刀CRUD脚手架而不是MVC
- github-actions - GitHub 操作错误:“需要顶级 'runs:' 部分”
- java - JUnit 错误:无法加载 ApplicationContext:违规资源:类路径资源
- unity3d - 无法生成具有客户端权限的游戏对象
- amazon-s3 - terraform 参考现有的 s3 存储桶和发电机表
- react-native - 在反应导航中使用 navigation.goBack 发送参数
- python - KeyError:'requestContext',FastAPI,Mangum,无服务器
- arrays - 尝试使用行和列进行文件 I/O,定位 FILE 时出现问题 *
- ssrs-2012 - SSRS 中的除法运算