The Problem
By default ReactNative doesn't support focusing next <TextInput/>
on submit.
Hack
Inspired by this StackOverflow answer
Use a Context named FormContext
that will create a LinkedList out of mounted <TextInput/>
.
Wrap a <TextInput/>
in a component, which will find and focus next <TextInput/>
from FormContext
.
Here is how the FormContext
and FormContextProvider
will look like.
// form.context.js
export const FormContext = createContext({});
let inputsLL = null;
let lastInput = null;
const FormContextProvider = ({ children }) => {
useEffect(() => {
inputsLL = null;
lastInput = null;
}, []);
return (
<FormContext.Provider
value={{
actions: {
addInput(name, ref) {
ref.name = name;
if (!inputsLL) {
inputsLL = ref;
lastInput = ref;
} else if (lastInput) {
lastInput.next = ref;
lastInput = ref;
}
},
removeInput(name) {
if (inputsLL) {
let node = inputsLL;
let parent = null;
do {
if (node.name === name) {
if (parent && node.next) {
parent.next = node.next;
} else if (parent && !node.next) {
parent.next = null;
} else if (!parent && node.next) {
inputsLL = node.next;
} else if (!parent && !node.next) {
inputsLL = null;
}
break;
}
parent = node;
node = node.next;
} while (node);
}
},
focusNext(name) {
if (inputsLL) {
let node = inputsLL;
do {
if (node.name === name) {
if (node.next) {
node.next.focus();
} else node.blur();
}
node = node.next;
} while (node);
}
},
},
inputs: inputsLL,
}}
>
{children}
</FormContext.Provider>
);
};
export default FormContextProvider;
Here is a <TextInput/>
wrapper implementation
// wrapped-input.js
export default function WrappedInput(props) {
let reference = useRef(null);
const { actions } = useContext(FormContext);
useEffect(() => {
//label must be unique
actions.addInput(props.label, reference);
return () => {
actions.removeInput(props.label);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [reference]);
return (
<TextInput
ref={(r) => (reference = r)}
blurOnSubmit={false}
onSubmitEditing={() => {
actions.focusNext(props.label);
}}
/>
)
}
Top comments (0)