怎么让TextInput获取或者失去焦点?focus()和blur()现在不支持吗?
-
单看代码没发现问题,如果那些if else的流程符合预期的话
打印结果呢?
-
@晴明 我打印this.search就是undefined的 我找不到原因
-
@晴明 我是想通过focus()和blur()来实现输入框是否获取焦点 但是我在这里就是获取不到ref
在我项目的其他地方我是可以通过this.refs获取到的 但是这里不行
对了 出问题的代码是依赖包里面的文件 我在改react-native-gifted-chat这个包的源代码 出现这个问题是因为我没有把它放在项目目录下吗?
-
undefined那就是ref没有执行咯,所以我说你那些if else的流程确定正确吗?这些基本逻辑都应该断点调试啊,方法是否按期望的顺序执行甚至是否有执行,是否按期望的输入值输入,期望的返回值返回等等,所有的调试都是这样啊。你文件放在哪无所谓啊(规不规范另说),反正最终都是揉到一起在内存里执行
-
@晴明 这些if else是正确的 因为我的视图是正确渲染了 所有其他逻辑都没有问题 就是这里的ref获取不到
-
@晴明 textInput所在的组件的父组件的代码是这样的:
/* eslint no-param-reassign: 0, no-use-before-define: ["error", { "variables": false }], no-return-assign: 0, no-mixed-operators: 0, react/sort-comp: 0 */ import PropTypes from 'prop-types'; import React from 'react'; import { Animated, Platform, StyleSheet, View } from 'react-native'; import ActionSheet from '@expo/react-native-action-sheet'; import moment from 'moment'; import uuid from 'uuid'; import * as utils from './utils'; import Actions from './Actions'; import Avatar from './Avatar'; import Bubble from './Bubble'; import SystemMessage from './SystemMessage'; import MessageImage from './MessageImage'; import MessageText from './MessageText'; import Composer from './Composer'; import Day from './Day'; import InputToolbar from './InputToolbar'; import LoadEarlier from './LoadEarlier'; import Message from './Message'; import MessageContainer from './MessageContainer'; import Send from './Send'; import Time from './Time'; import GiftedAvatar from './GiftedAvatar'; import { MIN_COMPOSER_HEIGHT, MAX_COMPOSER_HEIGHT, DEFAULT_PLACEHOLDER, TIME_FORMAT, DATE_FORMAT, } from './Constant'; global.inputRef = null; moment.locale('zh-cn', { months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'), weekdaysMin: '日_一_二_三_四_五_六'.split('_'), longDateFormat: { LT: 'Ah点mm分', LTS: 'Ah点m分s秒', L: 'YYYY-MM-DD', LL: 'YYYY年MMMD日', LLL: 'YYYY年MMMD日Ah点mm分', LLLL: 'YYYY年MMMD日ddddAh点mm分', l: 'YYYY-MM-DD', ll: 'YYYY年MMMD日', lll: 'YYYY年MMMD日Ah点mm分', llll: 'YYYY年MMMD日ddddAh点mm分' }, meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, meridiemHour: function (h, meridiem) { let hour = h; if (hour === 12) { hour = 0; } if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { return hour; } else if (meridiem === '下午' || meridiem === '晚上') { return hour + 12; } else { // '中午' return hour >= 11 ? hour : hour + 12; } }, meridiem: function (hour, minute, isLower) { const hm = hour * 100 + minute; if (hm < 600) { return '凌晨'; } else if (hm < 900) { return '早上'; } else if (hm < 1130) { return '上午'; } else if (hm < 1230) { return '中午'; } else if (hm < 1800) { return '下午'; } else { return '晚上'; } }, calendar: { sameDay: function () { return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT'; }, nextDay: function () { return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT'; }, lastDay: function () { return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT'; }, nextWeek: function () { let startOfWeek, prefix; startOfWeek = moment().startOf('week'); prefix = this.diff(startOfWeek, 'days') >= 7 ? '[下]' : '[本]'; return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; }, lastWeek: function () { let startOfWeek, prefix; startOfWeek = moment().startOf('week'); prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]'; return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; }, sameElse: 'LL' }, ordinalParse: /\d{1,2}(日|月|周)/, ordinal: function (number, period) { switch (period) { case 'd': case 'D': case 'DDD': return number + '日'; case 'M': return number + '月'; case 'w': case 'W': return number + '周'; default: return number; } }, relativeTime: { future: '%s内', past: '%s前', s: '几秒', m: '1 分钟', mm: '%d 分钟', h: '1 小时', hh: '%d 小时', d: '1 天', dd: '%d 天', M: '1 个月', MM: '%d 个月', y: '1 年', yy: '%d 年' }, week: { // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 dow: 1, // Monday is the first day of the week. doy: 4 // The week that contains Jan 4th is the first week of the year. } }); class GiftedChat extends React.Component { constructor(props) { super(props); // default values this._isMounted = false; this._keyboardHeight = 0; this._bottomOffset = 0; this._maxHeight = null; this._isFirstLayout = true; this._locale = 'en'; this._messages = []; this.state = { isInitialized: false, // initialization will calculate maxHeight before rendering the chat composerHeight: MIN_COMPOSER_HEIGHT, messagesContainerHeight: null, typingDisabled: false, }; this.onKeyboardWillShow = this.onKeyboardWillShow.bind(this); this.onKeyboardWillHide = this.onKeyboardWillHide.bind(this); this.onKeyboardDidShow = this.onKeyboardDidShow.bind(this); this.onKeyboardDidHide = this.onKeyboardDidHide.bind(this); this.onSend = this.onSend.bind(this); this.getLocale = this.getLocale.bind(this); this.onInputSizeChanged = this.onInputSizeChanged.bind(this); this.onInputTextChanged = this.onInputTextChanged.bind(this); this.onMainViewLayout = this.onMainViewLayout.bind(this); this.onInitialLayoutViewLayout = this.onInitialLayoutViewLayout.bind(this); this.invertibleScrollViewProps = { inverted: this.props.inverted, keyboardShouldPersistTaps: this.props.keyboardShouldPersistTaps, onKeyboardWillShow: this.onKeyboardWillShow, onKeyboardWillHide: this.onKeyboardWillHide, onKeyboardDidShow: this.onKeyboardDidShow, onKeyboardDidHide: this.onKeyboardDidHide, }; } static append(currentMessages = [], messages, inverted = true) { if (!Array.isArray(messages)) { messages = [messages]; } return inverted ? messages.concat(currentMessages) : currentMessages.concat(messages); } static prepend(currentMessages = [], messages, inverted = true) { if (!Array.isArray(messages)) { messages = [messages]; } return inverted ? currentMessages.concat(messages) : messages.concat(currentMessages); } getChildContext() { return { actionSheet: () => this._actionSheetRef, getLocale: this.getLocale, }; } componentWillMount() { const { messages, text } = this.props; this.setIsMounted(true); this.initLocale(); this.setMessages(messages || []); this.setTextFromProp(text); } componentWillUnmount() { this.setIsMounted(false); } componentWillReceiveProps(nextProps = {}) { const { messages, text } = nextProps; this.setMessages(messages || []); this.setTextFromProp(text); } initLocale() { if (this.props.locale === null || moment.locales().indexOf(this.props.locale) === -1) { this.setLocale('en'); } else { this.setLocale(this.props.locale); } } setLocale(locale) { this._locale = locale; } getLocale() { return this._locale; } setTextFromProp(textProp) { // Text prop takes precedence over state. if (textProp !== undefined && textProp !== this.state.text) { this.setState({ text: textProp }); } } getTextFromProp(fallback) { if (this.props.text === undefined) { return fallback; } return this.props.text; } setMessages(messages) { this._messages = messages; } getMessages() { return this._messages; } setMaxHeight(height) { this._maxHeight = height; } getMaxHeight() { return this._maxHeight; } setKeyboardHeight(height) { this._keyboardHeight = height; } getKeyboardHeight() { if (Platform.OS === 'android' && !this.props.forceGetKeyboardHeight) { // For android: on-screen keyboard resized main container and has own height. // @see https://developer.android.com/training/keyboard-input/visibility.html // So for calculate the messages container height ignore keyboard height. return 0; } return this._keyboardHeight; } setBottomOffset(value) { this._bottomOffset = value; } getBottomOffset() { return this._bottomOffset; } setIsFirstLayout(value) { this._isFirstLayout = value; } getIsFirstLayout() { return this._isFirstLayout; } setIsTypingDisabled(value) { this.setState({ typingDisabled: value, }); } getIsTypingDisabled() { return this.state.typingDisabled; } setIsMounted(value) { this._isMounted = value; } getIsMounted() { return this._isMounted; } // TODO: setMinInputToolbarHeight getMinInputToolbarHeight() { return this.props.renderAccessory ? this.props.minInputToolbarHeight * 2 : this.props.minInputToolbarHeight; } calculateInputToolbarHeight(composerHeight) { return composerHeight + (this.getMinInputToolbarHeight() - MIN_COMPOSER_HEIGHT); } /** * Returns the height, based on current window size, without taking the keyboard into account. */ getBasicMessagesContainerHeight(composerHeight = this.state.composerHeight) { return this.getMaxHeight() - this.calculateInputToolbarHeight(composerHeight); } /** * Returns the height, based on current window size, taking the keyboard into account. */ getMessagesContainerHeightWithKeyboard(composerHeight = this.state.composerHeight) { return this.getBasicMessagesContainerHeight(composerHeight) - this.getKeyboardHeight() + this.getBottomOffset(); } prepareMessagesContainerHeight(value) { if (this.props.isAnimated === true) { return new Animated.Value(value); } return value; } onKeyboardWillShow(e) { this.setIsTypingDisabled(true); this.setKeyboardHeight(e.endCoordinates ? e.endCoordinates.height : e.end.height); this.setBottomOffset(this.props.bottomOffset); const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(); if (this.props.isAnimated === true) { Animated.timing(this.state.messagesContainerHeight, { toValue: newMessagesContainerHeight, duration: 210, }).start(); } else { this.setState({ messagesContainerHeight: newMessagesContainerHeight, }); } } onKeyboardWillHide() { this.setIsTypingDisabled(true); this.setKeyboardHeight(0); this.setBottomOffset(0); const newMessagesContainerHeight = this.getBasicMessagesContainerHeight(); if (this.props.isAnimated === true) { Animated.timing(this.state.messagesContainerHeight, { toValue: newMessagesContainerHeight, duration: 210, }).start(); } else { this.setState({ messagesContainerHeight: newMessagesContainerHeight, }); } } onKeyboardDidShow(e) { if (Platform.OS === 'android') { this.onKeyboardWillShow(e); } this.setIsTypingDisabled(false); } onKeyboardDidHide(e) { if (Platform.OS === 'android') { this.onKeyboardWillHide(e); } this.setIsTypingDisabled(false); } scrollToBottom(animated = true) { if (this._messageContainerRef === null) { return; } this._messageContainerRef.scrollTo({ y: 0, animated }); } renderMessages() { const AnimatedView = this.props.isAnimated === true ? Animated.View : View; return ( <AnimatedView style={{ height: this.state.messagesContainerHeight, }} > <MessageContainer {...this.props} invertibleScrollViewProps={this.invertibleScrollViewProps} messages={this.getMessages()} ref={(component) => (this._messageContainerRef = component)} /> {this.renderChatFooter()} </AnimatedView> ); } onSend(messages = [], shouldResetInputToolbar = false) { if (!Array.isArray(messages)) { messages = [messages]; } messages = messages.map((message) => { return { ...message, user: this.props.user, createdAt: new Date(), _id: this.props.messageIdGenerator(), }; }); if (shouldResetInputToolbar === true) { this.setIsTypingDisabled(true); this.resetInputToolbar(); } this.props.onSend(messages); this.scrollToBottom(); if (shouldResetInputToolbar === true) { setTimeout(() => { if (this.getIsMounted() === true) { this.setIsTypingDisabled(false); } }, 100); } } resetInputToolbar() { if (this.textInput) { this.textInput.clear(); } this.notifyInputTextReset(); const newComposerHeight = MIN_COMPOSER_HEIGHT; const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight); this.setState({ text: this.getTextFromProp(''), composerHeight: newComposerHeight, messagesContainerHeight: this.prepareMessagesContainerHeight(newMessagesContainerHeight), }); } focusTextInput() { if (this.textInput) { this.textInput.focus(); } } onInputSizeChanged(size) { const newComposerHeight = Math.max(MIN_COMPOSER_HEIGHT, Math.min(MAX_COMPOSER_HEIGHT, size.height)); const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight); this.setState({ composerHeight: newComposerHeight, messagesContainerHeight: this.prepareMessagesContainerHeight(newMessagesContainerHeight), }); } onInputTextChanged(text) { if (this.getIsTypingDisabled()) { return; } if (this.props.onInputTextChanged) { this.props.onInputTextChanged(text); } // Only set state if it's not being overridden by a prop. if (this.props.text === undefined) { this.setState({ text }); } } notifyInputTextReset() { if (this.props.onInputTextChanged) { this.props.onInputTextChanged(''); } } onInitialLayoutViewLayout(e) { const { layout } = e.nativeEvent; if (layout.height <= 0) { return; } this.notifyInputTextReset(); this.setMaxHeight(layout.height); const newComposerHeight = MIN_COMPOSER_HEIGHT; const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight); this.setState({ isInitialized: true, text: this.getTextFromProp(''), composerHeight: newComposerHeight, messagesContainerHeight: this.prepareMessagesContainerHeight(newMessagesContainerHeight), }); } onMainViewLayout(e) { // fix an issue when keyboard is dismissing during the initialization const { layout } = e.nativeEvent; if (this.getMaxHeight() !== layout.height || this.getIsFirstLayout() === true) { this.setMaxHeight(layout.height); this.setState({ messagesContainerHeight: this.prepareMessagesContainerHeight(this.getBasicMessagesContainerHeight()), }); } if (this.getIsFirstLayout() === true) { this.setIsFirstLayout(false); } } renderInputToolbar() { const inputToolbarProps = { ...this.props, text: this.getTextFromProp(this.state.text), composerHeight: Math.max(MIN_COMPOSER_HEIGHT, this.state.composerHeight), onSend: this.onSend, onInputSizeChanged: this.onInputSizeChanged, onTextChanged: this.onInputTextChanged, textInputProps: { ...this.props.textInputProps, ref: (textInput) => (this.textInput = textInput), maxLength: this.getIsTypingDisabled() ? 0 : this.props.maxInputLength, }, }; if (this.props.renderInputToolbar) { return this.props.renderInputToolbar(inputToolbarProps); } return ( <InputToolbar {...inputToolbarProps} /> ); } renderChatFooter() { if (this.props.renderChatFooter) { const footerProps = { ...this.props, }; return this.props.renderChatFooter(footerProps); } return null; } renderLoading() { if (this.props.renderLoading) { return this.props.renderLoading(); } return null; } render() { if (this.state.isInitialized === true) { return ( <ActionSheet ref={(component) => (this._actionSheetRef = component)}> <View style={styles.container} onLayout={this.onMainViewLayout}> {this.renderMessages()} {this.renderInputToolbar()} </View> </ActionSheet> ); } return ( <View style={styles.container} onLayout={this.onInitialLayoutViewLayout}> {this.renderLoading()} </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, }); GiftedChat.childContextTypes = { actionSheet: PropTypes.func, getLocale: PropTypes.func, }; GiftedChat.defaultProps = { messages: [], text: undefined, placeholder: DEFAULT_PLACEHOLDER, messageIdGenerator: () => uuid.v4(), user: {}, onSend: () => { }, locale: null, timeFormat: TIME_FORMAT, dateFormat: DATE_FORMAT, isAnimated: Platform.select({ ios: true, android: false, }), loadEarlier: false, onLoadEarlier: () => { }, isLoadingEarlier: false, renderLoading: null, renderLoadEarlier: null, renderAvatar: undefined, showUserAvatar: false, onPressAvatar: null, renderAvatarOnTop: false, renderBubble: null, renderSystemMessage: null, onLongPress: null, renderMessage: null, renderMessageText: null, renderMessageImage: null, imageProps: {}, lightboxProps: {}, textInputProps: {}, listViewProps: {}, renderCustomView: null, renderDay: null, renderTime: null, renderFooter: null, renderChatFooter: null, renderInputToolbar: null, renderComposer: null, renderActions: null, renderSend: null, renderAccessory: null, onPressActionButton: null, bottomOffset: 0, minInputToolbarHeight: 44, keyboardShouldPersistTaps: Platform.select({ ios: 'never', android: 'always', }), onInputTextChanged: null, maxInputLength: null, forceGetKeyboardHeight: false, inverted: true, }; GiftedChat.propTypes = { messages: PropTypes.arrayOf(PropTypes.object), text: PropTypes.string, placeholder: PropTypes.string, messageIdGenerator: PropTypes.func, user: PropTypes.object, onSend: PropTypes.func, locale: PropTypes.string, timeFormat: PropTypes.string, dateFormat: PropTypes.string, isAnimated: PropTypes.bool, loadEarlier: PropTypes.bool, onLoadEarlier: PropTypes.func, isLoadingEarlier: PropTypes.bool, renderLoading: PropTypes.func, renderLoadEarlier: PropTypes.func, renderAvatar: PropTypes.func, showUserAvatar: PropTypes.bool, onPressAvatar: PropTypes.func, renderAvatarOnTop: PropTypes.bool, renderBubble: PropTypes.func, renderSystemMessage: PropTypes.func, onLongPress: PropTypes.func, renderMessage: PropTypes.func, renderMessageText: PropTypes.func, renderMessageImage: PropTypes.func, imageProps: PropTypes.object, lightboxProps: PropTypes.object, renderCustomView: PropTypes.func, renderDay: PropTypes.func, renderTime: PropTypes.func, renderFooter: PropTypes.func, renderChatFooter: PropTypes.func, renderInputToolbar: PropTypes.func, renderComposer: PropTypes.func, renderActions: PropTypes.func, renderSend: PropTypes.func, renderAccessory: PropTypes.func, onPressActionButton: PropTypes.func, bottomOffset: PropTypes.number, minInputToolbarHeight: PropTypes.number, listViewProps: PropTypes.object, keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled']), onInputTextChanged: PropTypes.func, maxInputLength: PropTypes.number, forceGetKeyboardHeight: PropTypes.bool, inverted: PropTypes.bool, textInputProps: PropTypes.object, }; export { GiftedChat, Actions, Avatar, Bubble, SystemMessage, MessageImage, MessageText, Composer, Day, InputToolbar, LoadEarlier, Message, MessageContainer, Send, Time, GiftedAvatar, utils, };
-
@1111mp 在render中ActionSheet有一个ref 这个会影响textInput的ref吗?
-
你看死的代码看不出其值的变化,
你要做的就是在ref中打上断点,在onpress里打上断点,在各个可疑的地方打上断点,然后观察this的值,this.search的值,直到发现在哪个地方不对,再反过来思考哪里的流程不对
-
@晴明 嗯 我刚刚在ref中加了调试 发现这个方法没有执行 现在在找没有执行ref的问题
-
@1111mp 其他地方的打印和调试代码都有执行
-
@晴明
这里的代码我有点看不懂 这里的ref应该是textInput的ref吧?是不是这里的问题导致?
-
@晴明 你好 我已经解决了这个问题 就是我最后贴出来的代码造成的 ref在父组件中已经传递并执行了 所以我不需要在子组件中使用ref 在textInput的父组件中是可以获取到的 真的非常感谢你 谢谢啊
-
不要轻易用{...this.props}这种笼统的写法(不可控,你根本不知道哪些属性重叠),你的问题就是{...this.props.textInputProps}里的ref覆盖了单独写的ref
-
@晴明 好的 谢谢 我会注意的