Plewis
Plewis

Reputation: 129

ReactJS & TypeScript - Get one random value of array

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.

Upvotes: 1

Views: 2093

Answers (1)

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

  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
  });
}

Upvotes: 2

Related Questions