ssc
ssc

Reputation: 9903

React Native: <string>.matchAll is not a function

I get a weird error when running my React Native app:

Some sample code:

const { url } = <incoming object>;
const reURL   = <my regex>;

console.debug('url:', url);
console.debug('typeof url:', typeof url);

matches = [...url.matchAll(reURL)];

Log output:

url: <as expected>
typeof url: string

Error message:

TypeError: url.matchAll is not a function. (In 'url.matchAll(reURL)', 'url.matchAll' is undefined)

Everything works fine on iOS, the error only occurs on Android.

Pretty up to date environment, updated all npm packages a couple of days ago.

Does anyone have the slightest idea where to even begin searching for a solution ?

Upvotes: 6

Views: 4224

Answers (4)

Kia Kaha
Kia Kaha

Reputation: 1791

Replacing the call to str.matchAll(regex) with the recursive function in this answer did the job perfectly for me.

Pasting here the function with TS support for completeness:

/**
 * Recursive function which replaces the usage of `str.matchAll(regex)` which happens to be troublesome on Android once compiled.
 * @param regex - regex expression to be executed. If passed with the `/g` global flag the result will return all matches.
 * @param str - string value to be searched for matches by the regex expression
 * @param matches - parameter used to pass on the current resulting array through recursion iterations
 * @returns array of all matches found while executing the regex
 */
export function findAllMatches(regex: RegExp, str: string, matches: RegExpExecArray[] = []) {
  const res = regex.exec(str)
  res && matches.push(res) && findAllMatches(regex, str, matches)
  return matches
}

Ensuring nobody in the codebase would try to use matchAll again could be achieved by adding the following es-lint rule:

"no-restricted-syntax": ["error", {
   "selector": "CallExpression[callee.property.name='matchAll']",
   "message": "You should use the findAllMatches function instead."
}]

Upvotes: 0

Juan Borda
Juan Borda

Reputation: 69

For us, this issue was solved by conditionally evaluating matchAll:

ourSring.matchAll?.(expr);

Our working theory is that the first time this method is accessed, some native async regex initialization is run, but takes some time to bind the method, resulting in undefined matchAll method. Subsequent evaluations work properly for us.

Upvotes: 0

foloinfo
foloinfo

Reputation: 693

You can use string.prototype.matchall to polyfill.

https://www.npmjs.com/package/string.prototype.matchall

import matchAll from 'string.prototype.matchAll'

matchAll.shim()

Upvotes: 1

I have the same issue. String.matchAll does not work for Android. You should use match instead matchAll.

Example:

const regex = new RegExp(text, 'ig');
const arr = string.match(regex);

You will get an array match regex

Upvotes: 1

Related Questions