【Rust】選択ソート

1件ずつ調べていく手法です。最小値の抽出は以下の通り。

fn main() {
    let data = [6, 15, 4, 2, 8, 5, 11, 9, 7, 13];

    let mut min = 0;
    for i in 0..data.len() {
        if data[min] > data[i] {
            min = i;
        }
    } 
    println!("minimal num:{}", data[min]);
}

### 選択ソート
n * (n – 1) / 2 の計算量が必要になる。もっとも小さいものを左から順番に並べていく。
mem::swap(&mut data[min], &mut data[i]);は使えない。

use std::mem;

fn main() {
    let mut data = [6, 15, 4, 2, 8, 5, 11, 9, 7, 13];

    for i in 0..data.len() {
        let mut min = i;
        let k = i + 1; 
        for j in k..data.len() {
            if data[min] > data[j] {
                min = j;
            }
        }
        // mem::swap(&mut data[min], &mut data[i]);
        data.swap(i, min);
    }   
    println!("sorted data:{:?}", data);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/rust`
sorted data:[2, 4, 5, 6, 7, 8, 9, 11, 13, 15]

なるほど、普段ソートとか考えたことなかったが、こうなってるのか。。面白いね。

[Vue.js] 初期値を入れてRange formの値と入力フォームを一致させる

range formもinput formも両方 v-modelの値を一致させる。

<div class="form-group">
                    <label for="customRange1" class="form-label">Request amount range</label>
                    <input type="range" class="form-range" id="customRange1" min="0" max="100" v-model="value">
                </div>
                <div class="form-group">
                    <label for="amount">amount:</label>
                    <input type="amount" name="amount" class="form-control" id="amount" v-model="value">
                </div>

初期値は設定するだけ。

    const app = new Vue({
        el: '#app',
        data: {
            title: '入力フォームバリデーション',
            name: '',
            value: 50,
        },

めちゃくちゃ簡単じゃん。もっと時間かかると思ったw

[Vue.js] vuelidateによるvalidation

公式
https://vuelidate.js.org/

これが一番しっくりくるなぁ。。正直Reactより使いやすい。

<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="utf-8">
 <title>title</title>
 <!-- <link rel="stylesheet" href="sample.css"> -->
 <!--[if lt IE 9]>
 <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
 <![endif]-->
 <!-- <script src="sample.js"></script> -->
 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" >
 <!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
 <!-- <script src="https://cdn.jsdelivr.net/npm/vue@3.2/dist/vue.global.js"></script> -->
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/vuelidate@0.7.4/dist/validators.min.js"></script>
 <script src="https://cdn.jsdelivr.net/npm/vuelidate@0.7.4/dist/vuelidate.min.js"></script>
 </head>
 
 <body>
<div id="app" class="container mt-5">
    <h2>{{title}}</h2>
    <!-- <pre>{{ $v }}</pre> -->
    <div class="row">
        <div class="col-sm-8">
            <form @submit.prevent="submitForm" action="/hoge">
                <div class="form-group">
                    <label for="name">名前:</label>
                    <input type="name" class="form-control" id="name" v-model="name" @blur="$v.name.$touch()">
                    
                    <div v-if="$v.name.$error">
                        <span v-if="!$v.name.required">名前が入力されていません。</span>
                        <span v-if="!$v.name.alphaNum">英数字で入力してください。</span>
                        <span v-if="!$v.name.minLength">5文字以上で入力してください。</span>
                        <span v-if="!$v.name.maxLength">10文字以下で入力してください。</span>
                        
                    </div>
                </div>
                <div class="form-group">
                    <label for="age">年齢:</label>
                    <input type="age" class="form-control" id="age" v-model="age">
                </div>
                <div class="form-group">
                    <label for="email">メールアドレス:</label>
                    <input type="email" class="form-control" id="email" v-model="email" @blur="$v.name.$touch()">
                    <div v-if="$v.email.$error">
                        <span v-if="!$v.email.required">メールアドレスが入力されていません。</span>
                        <span v-if="!$v.email.email">メールアドレスの形式が正しくありません。</span>
                    </div>
                </div>
                <button  type="submit" class="btn btn-info">送信</button>
                <!-- <button :disabled="$v.$invalid" type="submit" class="btn btn-info">送信</button> -->
            </form>
        </div>
    </div>
</div>
<script>
    Vue.use(window.vuelidate.default);
    const { required, email, maxLength, minLength, alphaNum } = window.validators;

    const app = new Vue({
        el: '#app',
        data: {
            title: '入力フォームバリデーション',
            name: '',
            age: '',
            email: '',
        },
        validations: {
            name: {
                required,
                alphaNum,
                minLength: minLength(4),
                maxLength: maxLength(10),
            },
            email: {
                required,
                email
            }
        },
        methods: {
            submitForm() {
                this.$v.$touch();
                if (this.$v.$invalid) {
                    console.log('バリデーションエラー');
                } else {
                    console.log('submit');
                }
                
            }
        }
    });
 </script>
 </body>
</html>

Vue.jsフォームバリデーションの基礎

 <div>
    <form 
    id="app"
    @submit="checkForm"
    action="https://vuejs.org/"
    method="post"
    >

    <p v-if="errors.length">
        <b>Please correct the following error(s):</b>
        <ul>
            <li v-for="error in errors">{{ error }}</li>
        </ul>
    </p>

    <p>
        <label for="name">Name</label>
        <input 
            id="name"
            v-model="name"
            type="text"
            name="name">
    </p>
    <p>
        <label for="age">Age</label>
        <input 
            id="age"
            v-model="age"
            type="number"
            name="age"
            min="0">
    </p>
    <p>
        <label for="movie">Favorite Movie</label>
        <select 
            id="movie"
            v-model="movie"
            name="movie">
            <option>Star Wars</option>
            <option>Vanilla Sky</option>
            <option>Atomic Blonde</option>
        </select>
    </p>

    <p>
        <input 
            type="submit"
            value="Submit"
        >
    </p>
 </div>
 <!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
 <!-- <script>
    console.log(Vue);
  </script> -->
<script>
 const app = new Vue({
        el: '#app',
        data: {
            errors: [],
            name: null,
            age: null,
            movie: null
        },
        methods: {
            checkForm: function (e) {
                if(this.name && this.age) {
                    return true;
                }

                this.errors = [];

                if(!this.name) {
                    this.errors.push('Name required.');
                }
                if(!this.age) {
                    this.errors.push('Age required.');
                }
                e.preventDefault();
        }
        }
    });
 </script>
 </body>
</html>

うん、これは分かります。

 <div>
    <form 
    id="app"
    @submit="checkForm"
    action="https://vuejs.org/"
    method="post"
    novalidate="true"
    >

    <p v-if="errors.length">
        <b>Please correct the following error(s):</b>
        <ul>
            <li v-for="error in errors">{{ error }}</li>
        </ul>
    </p>

    <p>
        <label for="name">Name</label>
        <input 
            id="name"
            v-model="name"
            type="text"
            name="name">
    </p>
    <p>
        <label for="email">Email</label>
        <input 
            id="email"
            v-model="email"
            type="email"
            name="email"
            >
    </p>
    <p>
        <label for="movie">Favorite Movie</label>
        <select 
            id="movie"
            v-model="movie"
            name="movie">
            <option>Star Wars</option>
            <option>Vanilla Sky</option>
            <option>Atomic Blonde</option>
        </select>
    </p>

    <p>
        <input 
            type="submit"
            value="Submit"
        >
    </p>
 </div>
 <!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
 <!-- <script>
    console.log(Vue);
  </script> -->
<script>
 const app = new Vue({
        el: '#app',
        data: {
            errors: [],
            name: null,
            email: null,
            movie: null
        },
        methods: {
            checkForm: function (e) {

                this.errors = [];

                if(!this.name) {
                    this.errors.push('Name required.');
                }
                if(!this.email) {
                    this.errors.push('Email required.');
                } else if (!this.validEmail(this.email)){
                    this.errors.push('Valid email required.');
                }

                if(!this.errors.length){
                    return true;
                }                
                e.preventDefault();
        },
        validEmail: function(email){
            var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
            return re.test(email);
        }
        }
    });
 </script>
 </body>
</html>

なるほど、わかってきた!

Vue.jsのバリデーション

 <div id="app">
    <div class="form-area__name">
        <p>名前</p>
        <input type="text" name="name" v-model="name">
        <p v-if="isInValidName" class="error">名前は4文字以上で入力してください。</p>
    </div>
    <div class="form-area__email">
        <p>メールアドレス</p>
        <input type="text" name="email" v-model="email">
        <p v-if="isInValidEmail" class="error">メールアドレスの形式で入力してください。</p>
    </div>
    <div class="form-area__tel">
        <p>電話番号</p>
        <input type="tel" name="tel" v-model="tel">
        <p v-if="isInValidTel" class="error">電話番号は8桁で入力してください。</p>
    </div>
 </div>
 
 <script>
    new Vue({
        el: '#app',
        data() {
            return {
                name: 'name',
                email: 'email@email.com',
                tel: '12345678'
            };
        },
        computed: {
            isInValidName() {
                return this.name.length < 4;
            },
            isInValidEmail(){
                const reg = new RegExp(/^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/);
                return !reg.test(this.email);
            },
            isInValidTel() {
                const tel = this.tel;
                const isErr = tel.length < 8 || isNaN(Number(tel));
                return isErr;
            }
        }
    });
 </script>

やりたいことはわかるが、挙動がなんかちゃうな…

【React】react-hook-formのバリデーション

import './App.css';
import { useForm } from 'react-hook-form';

function App() {
  const { register, 
  handleSubmit,
  formState: {errors},
  } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <div className="App">
      <h1>login</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" {...register('email', { required: true })} />
          {errors.email && <div>入力が必須の項目です</div>}
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            id="password"
            {...register('password')} type="password" 
          />
        </div>
        <div>
          <button type="submit">Login</button>
        </div>
      </form>
    </div>
  );
}

複数のエラーメッセージ

function App() {
  const { register, 
  handleSubmit,
  formState: {errors},
  } = useForm({
    criteriaMode: 'all',
  });

<label htmlFor="password">パスワード</label>
          <input
            id="password"
            {...register('password', {
              required: {
                value: true,
                message: '入力が必須の項目です。',
              },
              pattern: {
                value: /^[A-Za-z]+$/,
                message: 'アルファベットのみ入力してください。'
              },
              minLength: {
                value: 8,
                message: '8文字以上入力してください。'
              }
            })} type="password" 
          />
          {errors.password?.type === 'required' && (<div>{errors.password.types.required}</div>)}
          {errors.password?.type === 'pattern' && (<div>{errors.password.types.pattern}</div>)}
          {errors.password?.type === 'minLength' && (<div>8文字以上入力してください。</div>)}
        </div>

バリデーションのタイミングは制御できる
reValidateMode: ‘onSubmit’,
mode: ‘onChange’,

なるほど、何となくわかってきました。
さぁ、実装していきますか…

【React】react-hook-formを使ってみる

$ yarn add react-hook-form

react-hook-formを使わずに書いた場合 1

import './App.css';
import { useState } from 'react';

function App() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({
      email,
      password,
    });
  };

  const handleChangeEmail = (e) => {
    setEmail(e.target.value);
  };
  const handleChangePassword = (e) => {
    setPassword(e.target.value);
  };
  return (
    <div className="App">
      <h1>login</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" name="email" value={email} onChange={handleChangeEmail} />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            id="password"
            name="password"
            value={password}
            onChange={handleChangePassword}
            type="password"
          />
        </div>
        <div>
          <button type="submit">Login</button>
        </div>
      </form>
    </div>
  );
}

export default App;

react-hook-formを使わずに書いた場合 2

import './App.css';
import { useRef } from 'react';
import 

function App() {
  const emailRef = useRef(null);
  const passwordRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({
      email: emailRef.current.value,
      password: passwordRef.current.value,
    });
  };

  // const handleChangeEmail = (e) => {
  //   setEmail(e.target.value);
  // };
  // const handleChangePassword = (e) => {
  //   setPassword(e.target.value);
  // };
  return (
    <div className="App">
      <h1>login</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" name="email" ref={emailRef} />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            id="password"
            name="password"
            ref={passwordRef} type="password" 
          />
        </div>
        <div>
          <button type="submit">Login</button>
        </div>
      </form>
    </div>
  );
}

export default App;

### react-hook-formを使った場合

import './App.css';
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <div className="App">
      <h1>login</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" {...register('email')} />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            id="password"
            {...register('password')} type="password" 
          />
        </div>
        <div>
          <button type="submit">Login</button>
        </div>
      </form>
    </div>
  );
}

export default App;

registerに入っている値

const { name, ref, onChange, onBlur } = register('email');
//略
<input
  id="email"
  name={name}
  onChange={onChange}
  onBlur={onBlur}
  ref={ref}
/>

Reactでカウンターを作る

import React, { Component } from 'react';

const App = () => {
  return <Counter />
}

class Counter extends Component
{
  constructor(props)
  {
    super(props);
    this.state = {
      value : 0
    }
  }

  onIncrement = () => {
    this.setState({ value : this.state.value + 1});
  }

  onDecrement = () => {
    this.setState({ value : this.state.value - 1});
  }

  render()
  {
    return (
      <div>
        <div>
          Count value: {this.state.value}
        </div>
          
        <div>
        <button type="button" onClick={this.onIncrement}>+</button>
        <button type="button" onClick={this.onDecrement}>-</button>
        </div>
      </div>
    );
  }
}
export default App;

なるほど、面白いです^^

Reactで作ったコンポーネントをWebページに埋め込む

まず、Rectで作った簡単なjsファイル

App.js

import React from 'react';
import ReactDOM from "react-dom";

const App = () => {
  
  return (
    <div>
      <h1>hello world { 1 + 2}</h1>
    </div>
  )
  
}

export default App;

ファイルをbuidします。

$ npm run build

すると、buid/static/js にファイルが生成されているので、これを埋め込みます。
ここでは main.50873ce4.jsとなっていました。

<body>
    <h1>hello world!</h1>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="main.js" crossorigin></script>
</body>

なるほど、フッターにインラインで記述するのではなく、Node JSで開発して、それをminifyしてコンポーネントとして埋め込むのね。
何となくReactの使い方は理解しました。

Reactの基礎 [環境構築]

$ npm -v
10.9.2
$ node -v
v22.13.1
$ yarn –version
bash: yarn: command not found

$ sudo npm install –global yarn
$ yarn –version
1.22.22

$ yarn create react-app helloworld
$ cd helloworld
$ ls
node_modules package.json public README.md src yarn.lock

$ yarn start

src/App.js

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

修正する

import React from 'react';

const App = () => {
  return (
    <div>
      <h1>hello world</h1>
    </div>
  )
}

export default App;

ちょっと思い出してきました。