Categories
discuss

How can I add unique keys to React/MUI Autocomplete component?

I’m trying to create a Material-UI Autocomplete component that essentially just displays search results to the user. Some of the options’ names will be duplicates, but they will all have unique IDs. I’ve been trying to fix the following warning for hours and I can’t figure it out.

index.js:1 Warning: Encountered two children with the same key, Name B. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

I’ve tried adding a key={} to numerous places throughout the code, all to no avail.

Code is attached below, and I’m quite new to this so any suggestions for how to improve the rest of the code generally would also be welcome.

const SearchField = () => {
    const [open, setOpen] = React.useState(false)
    const [searchQuery, setSearchQuery] = React.useState('')
    const [searchResults, setSearchResults] = React.useState([])
    const loading = true //later

    const debounced = useDebouncedCallback(
        async searchQuery => {
            if (searchQuery) {
                let result = await doSearch(searchQuery)
                if (result.status === 200) {
                    setSearchResults(result.data)
                } else {
                    console.error(result)
                }
            }
        },
        1000
    )

    const handleInputChange = e => {
        if (e.target.value && e.target.value !== searchQuery) {
            debounced(e.target.value)
            setSearchQuery(e.target.value)
        }
    }

    const options = [{
        name: 'Name A',
        id: 'entry_0597856'
    },{
        name: 'Name B',
        id: 'entry_3049854'
    },{
        name: 'Name B',
        id: 'entry_3794654'
    },{
        name: 'Name C',
        id: 'entry_9087345'
    }]


    return (
        <Autocomplete
            id='search_freesolo'
            freeSolo
            selectOnFocus
            clearOnBlur
            handleHomeEndKeys
            autoHighlight
            onInputChange={handleInputChange}
            open={true}
            onOpen={() => setOpen(true)}
            onClose={() => setOpen(false)}
            loading={loading}
            key={option => option.id}

            options={options}
            getOptionLabel={option => option.name}

            renderOption={(props, option) => (
                <Box
                    component='li'
                    {...props}
                >
                    {option.name}
                </Box>
            )}

            renderInput={params => {
                return (
                    <TextField
                        {...params}
                        required
                        id="search_bar"
                        label="Search"
                        InputProps={{
                            ...params.InputProps,
                            endAdornment: (
                                <React.Fragment>
                                    {loading ? <CircularProgress size={18} /> : null}
                                    {params.InputProps.endAdornment}
                                </React.Fragment>
                            )
                        }}
                    />
                )}
            }
            
        />
    )
}

Answer

You can define your own renderOption that can return the list item with a correct key value. Your code complains about the duplicated keys because by default, Autocomplete uses the getOptionLabel(option) to retrieve the key:

<Autocomplete
  renderOption={(props, option) => {
    return (
      <li {...props} key={option.id}>
        {option.name}
      </li>
    );
  }}
  renderInput={(params) => <TextField {...params} label="Movie" />}
/>

If it still doesn’t work, check your props order, you need to declare the key prop last, if you put it before the props provided by the callback:

<Box component='li' key={key} {...props}

Then it will be overridden by the props.key from MUI. It should be like this:

<Box component='li' {...props} key={key}

Live Demo

Codesandbox Demo

Categories
discuss

State is not updated in StrictMode

After some trial I discovered following problem occurs in strict mode. I would be interested if someone can explain why.

Take this simple example where inside render I am just scheduling a timeout which updates state:

Example:

let firstRender = true; // Normally I would use ref but I was playing with example

export default function App() {
  let [data, setData] = React.useState({ name: 'Nick' });

  // Schedule a timeout on first render
  if (firstRender) {
    setTimeout(() => {
      console.log('Running');

      setData((ps) => ({
        ...ps,
        name: 'Paul',
      }));
    }, 1000);
  }

  console.log('Running render');
  firstRender = false;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>Start editing to see some magic happen :)</p>
    </div>
  );
}

If you run this example without Strict mode, then you will see “Paul” on screen after one second, as I was expecting.

If you use Strict mode, it will always show “Nick” on screen. Idea why?

UPDATE: it seems using useRef instead of the global variable firstRender fixes this problem also in Strict mode. Curious why that’s the case?

Answer

This is due to the fact that strict mode intentionally invokes your function component body twice (when in dev mode) to help spot unintended side effects.

On the second invocation, your firstRender variable is false so your setTimeout doesn’t run.

Important to note that this second invocation isn’t just a re-render like you’d get from a state update. It’s a second invocation of the entire component body. State is not preserved. React invokes your component function once, discards the result, and invokes it a second time to get the output.

From the docs:

Because the above methods might be called more than once, it’s important that they do not contain side-effects.

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Function component bodies
Categories
discuss

P5 image gallery animation

I am trying to dynamically load a set of images and translate them in the Z direction at a constant speed while having randomised values for the X and Y

I am working with the following code and I am stuck on how to use the image texture property.

I get a blank black canvas on rendering the following code I worked with. Any help will be appreciated.

let imgs = [];
let imgs_arr = [];
let num = 15;

function preload() {
      for (let i = 0; i < num; i++) {
    imgs[i] = loadImage("https://picsum.photos/400/400/?image=" + i * 10);
  }
}

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  colorMode(HSB, 360, 100, 100, 100);
  for (let i = 0; i < num; i++) {
    let x = random(-width / 2, width / 2);
    let y = random(-height / 2, height / 2);
    let z = random(-width*5, width/2);
        let texture = new Type(imgs[i], x, y, z)
    imgs_arr.push(texture);
  }
}

function draw() {
  background(0,0,0);
    orbitControl();
  for (let i = 0; i < num; i++) {
    imgs_arr[i].update();
    imgs_arr[i].display();
  }
}

class Type {
  constructor(_img, _x, _y, _z) {
    this.img = _img;
    this.x = _x;
    this.y = _y;
    this.z = _z;
  }

  update() {
    this.z += 10;
    if(this.z > width/2){
        this.z = -width*5;
    }
  }
    

  display() {
    push();
    translate(this.x, this.y, this.z);
        texture(this.img)
    pop();
  }
}

Answer

Just from reading the docs it looks as though you’re missing a key component. Let’s say you want to draw the image on a box, you’d need to add the following after your texture:

box(width / 2);

Here’s the running example:

let imgs = [];
let imgs_arr = [];
let num = 15;

function preload() {
      for (let i = 0; i < num; i++) {
    imgs[i] = loadImage("https://picsum.photos/400/400/?image=" + i * 10);
  }
}

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  colorMode(HSB, 360, 100, 100, 100);
  for (let i = 0; i < num; i++) {
    let x = random(-width / 2, width / 2);
    let y = random(-height / 2, height / 2);
    let z = random(-width*5, width/2);
        let texture = new Type(imgs[i], x, y, z)
    imgs_arr.push(texture);
  }
}

function draw() {
  background(0,0,0);
    orbitControl();
  for (let i = 0; i < num; i++) {
    imgs_arr[i].update();
    imgs_arr[i].display();
  }
}

class Type {
  constructor(_img, _x, _y, _z) {
    this.img = _img;
    this.x = _x;
    this.y = _y;
    this.z = _z;
  }

  update() {
    this.z += 10;
    if(this.z > width/2){
        this.z = -width*5;
    }
  }
    

  display() {
    push();
    translate(this.x, this.y, this.z);
    texture(this.img)
    box(width / 2);
    pop();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js" integrity="sha512-N4kV7GkNv7QR7RX9YF/olywyIgIwNvfEe2nZtfyj73HdjCUkAfOBDbcuJ/cTaN04JKRnw1YG1wnUyNKMsNgg3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Categories
discuss

Using lookahead, how to ensure at least 4 alphanumeric chars are included + underscores

I’m trying to make sure that at least 4 alphanumeric characters are included in the input, and that underscores are also allowed.

The regular-expressions tutorial is a bit over my head because it talks about assertions and success/failure if there is a match.

^w*(?=[a-zA-Z0-9]{4})$

my understanding:

w –> alphanumeric + underscore

* –> matches the previous token between zero and unlimited times ( so, this means it can be any character that is alphanumeric/underscore, correct?)

(?=[a-zA-Z0-9]{4}) –> looks ahead of the previous characters, and if they include at least 4 alphanumeric characters, then I’m good.

Obviously I’m wrong on this, because regex101 is showing me no matches.

Answer

Your pattern ^w*(?=[a-zA-Z0-9]{4})$ does not match because:

  • ^w* Matches optional word characters from the start of the string, and if there are only word chars it will match until the end of the string
  • (?=[a-zA-Z0-9]{4}) The positive lookahead is true, if it can assert 4 consecutive alphanumeric chars to the right from the current position. The w* allows backtracking, and can backtrack 4 positions so that the assertion it true.
  • But the $ asserts the end of the string, which it can not match as the position moved 4 steps to the left to fulfill the previous positive lookahead assertion.

Using the lookahead, what you can do is assert 4 alphanumeric chars preceded by optional underscores.

If the assertion is true, match 1 or more word characters.

^(?=(?:_*[a-zA-Z0-9]){4})w+$

The pattern matches:

  • ^ Start of string
  • (?= Positive lookahead, asser what is to the right is
    • (?:_*[a-zA-Z0-9]){4} Repeat 4 times matching optional _ followed by an alphanumeric char
  • ) Close the lookahead
  • w+ Match 1+ word characters (which includes the _)
  • $ End of string

Regex demo

Categories
discuss

Does App Bundles (AAB) automatically use APK Signature Scheme v2?

I am reading some Android 11 updates documentation and apparently it is required to implement APK Signature Scheme v2. Does the AAB format do this already?

Answer

The Android App Bundle is only a publishing format. The mandate of the signature v2 scheme applies to APKs that are installed on the device. When Google Play generates the APKs from the App Bundle, it uses signature v2 scheme (or more recent), so if you publish to Google Play, you’re sorted.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..