React + Redux - 当输入具有来自状态的值时,输入 onChange 非常慢
React + Redux - Input onChange is very slow when typing in when the input have a value from the state
我得到了我的输入,其中填充了我所在州的值。
<input id="flashVars" name="flashVars" type="text" value={settings.flashVarsValue} disabled={isDisabled} onChange={handleChange} />
Settings
是我对 Redux 的看法。当我将一个值放入我的输入时,我必须指定一个 onChange
函数。这是我的 onChange 函数:
handleFlashVarsChange(e) {
let { dispatch } = this.props;
dispatch( changeFlashVarsValue(e.target.value) );
}
它改变输入值的状态值flashVarsValue
。但是当我输入我的输入时,它会滞后。我不明白为什么每次更改输入值时都要调用调度程序。
有什么办法可以减少延迟吗?
我的减速机:
import { ACTIONS } from '../utils/consts';
const initialState = {
...
flashVarsValue: '',
...
};
export function formSettings(state = initialState, action = '') {
switch (action.type) {
...
case ACTIONS.CHANGE_FLASHVARS_VALUE:
return Object.assign({}, state, {
flashVarsValue: action.data
});
default:
return state;
}
}
我的操作:
export function changeFlashVarsValue(data) {
return {
type: ACTIONS.CHANGE_FLASHVARS_VALUE,
data: data
}
}
谢谢
我在编辑具有一百万行的网格时遇到了类似的问题,所以我所做的是更改更新逻辑,在您的情况下 handleChange
仅在事件 [=11] 上调用=] 而不是 onChange
。这只会在您失去焦点时触发更新。但不知道这是否是您满意的解决方案。
这里的问题可能是重新渲染。您将 "settings"(您的整个状态)传递给包含 "input" 的组件,而我们不知道您的其余连接组件如何耦合到状态。检查是否由于状态对象的变化,您重新渲染的不仅仅是每次击键时的输入。解决方案是更直接地从 mapStateToProps 传递你需要的状态的特定部分(在这种情况下,可能只传递 "flashVarsValue" 如果这就是这个组件所需要的,并确保其他组件也没有传递整个状态)并使用 PureRenderMixin 或 Dan Abramov 的 https://github.com/gaearon/react-pure-render 如果你使用 ES6 组件不重新渲染,如果你的道具没有改变
我的答案是使用 shouldComponentUpdate 生命周期钩子。这已经在 Mike Boutin(大约一年前 :))的评论中作为答案给出了,但是一个例子可能会帮助这里的下一位访问者。
我遇到了类似的问题,文本输入丢失,而且速度慢且跳动。我在我的 onChange 事件中使用 setState 来更新 formData。
我发现随着状态的改变,表单在每次按键时都会进行完整的重新渲染。所以为了阻止这个,我覆盖了函数:
shouldComponentUpdate(nextProps, nextState) {
return this.state.formErrors !== nextState.formErrors);
}
我在提交表单时显示一个错误通知面板,其中包含任何新的或更改的验证错误,这是我唯一需要重新呈现的时间。
如果您没有子组件,您可能只需将表单组件的 shouldComponentUpdate 设置为始终 return false。
我知道这是一个老问题,但如果你想在文本输入上触发 onChange,你可能想要去抖动你的事件。 This thread 很好地分解了它,但我认为这适用于操作示例:
import debounce from 'debounce'
function debounceEventHandler(...args) {
const debounced = debounce(...args)
return function (e) {
e.persist();
return debounced(e);
}
}
const Container = React.createClass({
handleFlashVarsChange(e) {
let { dispatch } = this.props;
//basic redux stuff
this.props.changeFlashVarsValue(e.target.value));
},
render() {
const handleChange = debounceEventHandler(this.handleFlashVarsChange, 15);
return (
<input id="flashVars" onChange={handleChange} />
)
}
}
//...prep and return your redux container
答案不是在每次击键时都重新渲染您的组件,只有在用户停止输入时才重新渲染。像这样:
shouldComponentUpdate(nextProps, nextState) {
if (!textInputReRender)
return false;
else
return true;
}
onTextInputChange = (propName, propValue) => {
if (inputChangeTimerId)
clearTimeout(inputChangeTimerId);
inputChangeTimerId = setTimeout(() => {
inputChangeTimerId = null;
const newState = {};
textInputReRender = true;
newState[propName] = propValue;
this.setState(newState);
}, 500);
textInputReRender = false;
}
改用onChangeText
import { TextInput, View} from "react-native";
import { connect } from "react-redux";
import React, { Component, useState } from "react";
function SearchTextInput(props) {
const { keyword = "", setKeyword } = props;
return (
<TextInput
style={styles.searchInputText}
placeholder={"placeholder here"}
value={keyword}
onChangeText={setKeyword(t)}
/>
);
}
const mapStateToProps = state => {
return {
keyword: state.search.keyword,
search: state.search
};
};
const mapDispatchToProps = dispatch => ({
setKeyword: payload => dispatch(({type:'updateSearchText', keyword: payload }))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(SearchTextInput);
当你有一个复杂的页面时,这个问题很常见,因为你更新状态时总是需要重新渲染。所以你可以感觉到打字时很慢。
我找到了一个解决方案: React 的生命周期运行 by component。所以你可以创建其他组件并管理你的事件,比如 onChange,在你可以调用 onBlur 之后,这是由道具为他传递的。它对我有用:
import React, {Fragment, useState, useEffect} from 'react';
import TextField from '@material-ui/core/TextField';
export function InputText(props) {
const [value, setValue] = useState("");
const {onBlur = (e) => {console.log(e)}, name='name', defaultValue= 'Default', type='text', label='Label'} = props
useEffect(() => {
// console.log(value);
})
return (
<label>
<TextField
name={name}
label={label}
onBlur={e => onBlur(e)}
type={type}
value={value}
onChange={e => setValue(e.target.value)}
/>
</label>
);
}
class Sample extends React.Component {
handleBlurInput = e => {
this.setState({ [e.target.name]: e.target.value });
};
render() {
return (
<InputText name="nome" label="Label Sample" defaultValue={this.state.nome} onBlur={this.handleBlurInput.bind(this)} />
// Complex app ....
);
}
}
我得到了我的输入,其中填充了我所在州的值。
<input id="flashVars" name="flashVars" type="text" value={settings.flashVarsValue} disabled={isDisabled} onChange={handleChange} />
Settings
是我对 Redux 的看法。当我将一个值放入我的输入时,我必须指定一个 onChange
函数。这是我的 onChange 函数:
handleFlashVarsChange(e) {
let { dispatch } = this.props;
dispatch( changeFlashVarsValue(e.target.value) );
}
它改变输入值的状态值flashVarsValue
。但是当我输入我的输入时,它会滞后。我不明白为什么每次更改输入值时都要调用调度程序。
有什么办法可以减少延迟吗?
我的减速机:
import { ACTIONS } from '../utils/consts';
const initialState = {
...
flashVarsValue: '',
...
};
export function formSettings(state = initialState, action = '') {
switch (action.type) {
...
case ACTIONS.CHANGE_FLASHVARS_VALUE:
return Object.assign({}, state, {
flashVarsValue: action.data
});
default:
return state;
}
}
我的操作:
export function changeFlashVarsValue(data) {
return {
type: ACTIONS.CHANGE_FLASHVARS_VALUE,
data: data
}
}
谢谢
我在编辑具有一百万行的网格时遇到了类似的问题,所以我所做的是更改更新逻辑,在您的情况下 handleChange
仅在事件 [=11] 上调用=] 而不是 onChange
。这只会在您失去焦点时触发更新。但不知道这是否是您满意的解决方案。
这里的问题可能是重新渲染。您将 "settings"(您的整个状态)传递给包含 "input" 的组件,而我们不知道您的其余连接组件如何耦合到状态。检查是否由于状态对象的变化,您重新渲染的不仅仅是每次击键时的输入。解决方案是更直接地从 mapStateToProps 传递你需要的状态的特定部分(在这种情况下,可能只传递 "flashVarsValue" 如果这就是这个组件所需要的,并确保其他组件也没有传递整个状态)并使用 PureRenderMixin 或 Dan Abramov 的 https://github.com/gaearon/react-pure-render 如果你使用 ES6 组件不重新渲染,如果你的道具没有改变
我的答案是使用 shouldComponentUpdate 生命周期钩子。这已经在 Mike Boutin(大约一年前 :))的评论中作为答案给出了,但是一个例子可能会帮助这里的下一位访问者。
我遇到了类似的问题,文本输入丢失,而且速度慢且跳动。我在我的 onChange 事件中使用 setState 来更新 formData。
我发现随着状态的改变,表单在每次按键时都会进行完整的重新渲染。所以为了阻止这个,我覆盖了函数:
shouldComponentUpdate(nextProps, nextState) {
return this.state.formErrors !== nextState.formErrors);
}
我在提交表单时显示一个错误通知面板,其中包含任何新的或更改的验证错误,这是我唯一需要重新呈现的时间。
如果您没有子组件,您可能只需将表单组件的 shouldComponentUpdate 设置为始终 return false。
我知道这是一个老问题,但如果你想在文本输入上触发 onChange,你可能想要去抖动你的事件。 This thread 很好地分解了它,但我认为这适用于操作示例:
import debounce from 'debounce'
function debounceEventHandler(...args) {
const debounced = debounce(...args)
return function (e) {
e.persist();
return debounced(e);
}
}
const Container = React.createClass({
handleFlashVarsChange(e) {
let { dispatch } = this.props;
//basic redux stuff
this.props.changeFlashVarsValue(e.target.value));
},
render() {
const handleChange = debounceEventHandler(this.handleFlashVarsChange, 15);
return (
<input id="flashVars" onChange={handleChange} />
)
}
}
//...prep and return your redux container
答案不是在每次击键时都重新渲染您的组件,只有在用户停止输入时才重新渲染。像这样:
shouldComponentUpdate(nextProps, nextState) {
if (!textInputReRender)
return false;
else
return true;
}
onTextInputChange = (propName, propValue) => {
if (inputChangeTimerId)
clearTimeout(inputChangeTimerId);
inputChangeTimerId = setTimeout(() => {
inputChangeTimerId = null;
const newState = {};
textInputReRender = true;
newState[propName] = propValue;
this.setState(newState);
}, 500);
textInputReRender = false;
}
改用onChangeText
import { TextInput, View} from "react-native";
import { connect } from "react-redux";
import React, { Component, useState } from "react";
function SearchTextInput(props) {
const { keyword = "", setKeyword } = props;
return (
<TextInput
style={styles.searchInputText}
placeholder={"placeholder here"}
value={keyword}
onChangeText={setKeyword(t)}
/>
);
}
const mapStateToProps = state => {
return {
keyword: state.search.keyword,
search: state.search
};
};
const mapDispatchToProps = dispatch => ({
setKeyword: payload => dispatch(({type:'updateSearchText', keyword: payload }))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(SearchTextInput);
当你有一个复杂的页面时,这个问题很常见,因为你更新状态时总是需要重新渲染。所以你可以感觉到打字时很慢。
我找到了一个解决方案: React 的生命周期运行 by component。所以你可以创建其他组件并管理你的事件,比如 onChange,在你可以调用 onBlur 之后,这是由道具为他传递的。它对我有用:
import React, {Fragment, useState, useEffect} from 'react';
import TextField from '@material-ui/core/TextField';
export function InputText(props) {
const [value, setValue] = useState("");
const {onBlur = (e) => {console.log(e)}, name='name', defaultValue= 'Default', type='text', label='Label'} = props
useEffect(() => {
// console.log(value);
})
return (
<label>
<TextField
name={name}
label={label}
onBlur={e => onBlur(e)}
type={type}
value={value}
onChange={e => setValue(e.target.value)}
/>
</label>
);
}
class Sample extends React.Component {
handleBlurInput = e => {
this.setState({ [e.target.name]: e.target.value });
};
render() {
return (
<InputText name="nome" label="Label Sample" defaultValue={this.state.nome} onBlur={this.handleBlurInput.bind(this)} />
// Complex app ....
);
}
}