1

I've made a "ToDo" sort of small project, but instead its a list of names. I type a name in and add it to the array. Then I can also delete each item.

Now I want to press a button that randomly chooses one of the items/names within in the array and displays the name. I'm really struggling to figure out how to write the code for this (I'm new to TypeScript).

I can console.log a random name at a time by using the state.

Console.log random name from array

<button onClick={() => console.log((this.state.names[Math.floor(Math.random() * this.state.names.length)]))}>Add name</button>

NameList.tsx

import * as React from 'react';
import {RouteComponentProps} from "react-router-dom";


interface IState {
    currentName: string;
    names: Array<IList>
}


interface IList {
    id: number,
    value: string,
}

export default class List extends React.Component<RouteComponentProps, IState> {
    constructor(props: RouteComponentProps) {
        super(props);

        this.state = {
            currentName: "",
            names: []
        }
    }
    public handleSubmit(e: React.FormEvent<HTMLFormElement>): void {
        e.preventDefault();
        this.setState({
            currentName: "",
            names: [
                ...this.state.names,
                {
                    id: this._timeInMilliseconds(),
                    value: this.state.currentName,

                }
            ]
        })
    }

    public onChange(e: any): void {
        this.setState({
            currentName: e.target.value
        })
    }

    public removeUser(id: number): void {
        const filteredTasks: Array<IList> = this.state.names.filter((task: IList) => task.id !== id);
        this.setState({
            names: filteredTasks
        });
    }

    public renderList(): JSX.Element[] {
            return this.state.names.map((task: IList, index: number) => {
                return (
                    <div key={task.id} className="user">
                        <span className={task.completed ? "is-completed" : ""}>{task.value}</span>
                        <button onClick={() => this.removeUser(task.id)}> Delete </button>
                    </div>
                )
            });
        }


    public render(): JSX.Element {
        return (
            <div className={"header col-lg-12 form-wrapper"}>
                <h1> Add names to the list </h1>
                <div className="alert alert-info" role="alert">
                    <p>Press the button to select a random name from the list</p>
                    <button>Get random name</button>
                    <section>
                        {this.renderList()[Math.floor(Math.random() * this.state.names.length)]}
                    </section>
                </div>
                <form onSubmit={(e) => this.handleSubmit(e)}>
                    <input type="text" className="tdl-input" placeholder="Add a name to the list"
                           value={this.state.currentName}
                           onChange={(e) => this.onChange(e)}
                    />
                    <button type="submit">Add name</button>
                </form>
                <section>
                    {this.renderList()}
                </section>
            </div>
        );
    }

    private _timeInMilliseconds(): number {
        const date: Date = new Date();
        return date.getTime();
    }
}

Hope someone can guide me in the right direction - I believe I need to make a function that takes the array and gets a random value, but I don't know which array function to use to do this.

Additionally, I'm trying to get the random name to never show twice in a row - I believe I need to store the value in a new array somehow, unsure though.

1 Answer 1

2
  1. Add one state variable randomIndex

    this.state = {
        currentName: "",
        randomIndex: 0,
        names: []
    }
    
  2. Have a method to set random index

    public setRandomIndex(): void {
      const randomIndex: number = Math.floor(Math.random() * this.state.names.length);  
      this.setState({
            randomIndex
        });
    }
  1. update button and section. Use randomIndex and display item from array.
    <button onClick={() => this.setRandomIndex()}>Get random name</button>
    <section>
      {this.renderList()[this.state.randomIndex]}
    </section>

Update: Adding way to avoid having same random index. 1) use the setRandomIndex2 method instead of setRandomIndex
2) Initialise the state variable randomList: [] in constructor.
Basically maintain random index list, add to this only when not repeat and make sure to reset list when the size reaches to same as name list.

public setRandomIndex2(): void {
  let randomList = this.state.randomList;

  if (randomList.length === this.state.names.length) {
    randomList = [];
  }

  let randomIndex: number = Math.floor(Math.random() * this.state.names.length);
  while (randomList.includes(randomIndex)) {
    randomIndex = Math.floor(Math.random() * this.state.names.length);
  }

  randomList.push(randomIndex);

  this.setState({
    randomList,
    randomIndex
  });
}
Sign up to request clarification or add additional context in comments.

3 Comments

Makes sense - thanks a lot. Any idea how to make sure it does not show the same result twice?
@Penny, glad to hear. I just updated answer with alternate method to address this. This should work.
Not entirely sure why it works, but yes it works. Could you explain it more - I would appreciate that. My understanding is you make an empty array and take Math floor of the array, picking a random name. I don't understand how it avoids showing twice though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.