63
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaScriptの基礎をすっ飛ばして、React,Next.jsを使うとハマりがちなエラー3選

Last updated at Posted at 2022-06-23

この記事の対象者

・JavaScriptを学び切らずに、ReactやNext.jsなどから始めた人
・JavaScriptにほぼ触れていないけれど、React、Next.jsなどのJavaScriptフレームワーク・ライブラリを実務で挑戦してみたい人
・今現在、React、Next.jsで仕事をしているけど、ちんぷんかんぷんになって困っている人

この記事を読むメリット

・心の底から、「生のJavaScriptを学ばなきゃな!(汗)」ってなれる
・ReactやNext.jsで仕事をし始めてぶつかる壁を事前に知れる
・なんでReactでうまいこと実装が進まないのかが腑に落ちる

結論

・ライブラリ(React)やフレームワーク(Next.js)で、いきなりJavaScriptを始めるのではなく、まずは、最低限はJavaScriptの文法や簡単な実装はやっておくべし

生のJavaScriptをまずは学ぶべき3つの理由

1、JavaScriptの基礎がないと、エラーや意図した挙動でない時に、その原因の特定に莫大な時間を費やしてしまうから
2、別のライブラリやフレームワークに対応しにくいから(フロントエンドの変化スピードはとてつもないので、React以外を触ることになる可能性も高い)
3、「2、」とかぶるかもですが、React ,Vue ,Angularなどのあらゆるライブラリ、フレームワークの基盤なので、学び効率が最も高いから

JavaScriptの知識不足でぶち当たる壁は、幾度となくあるのですが、僕自身が初歩で、ぶち当たった壁を3つに絞って紹介しますね。

ケース1:map関数を覚えて、楽しくなってきた頃に遭遇しがちなやたらめったらmapをぶん回してガンギレされるアレ

JavaScriptの仕事は、mapをとりあえずぶん回してればいいんでしょ?と、調子に乗って、いつも通りmapを回していると...ん?

エ、エラア...?(半べそ)

error
TypeError: object.map is not a function

ぴえええん、mapが使えないだって!?
まぁ、冷静に考えてみれば、エラー内容の通りで、オブジェクトにはmapは使えないよ
ということですね。

公式にも書いてありますし。
map関数は、「配列」に対して、使える関数だよって。
誰もオブジェクトに使えるなんて言ってないんです、と当時の自分に優しく言ってあげたい。

下記のように、ノイローゼになるくらい耳元で囁きたい。(嘘です)

map関数は、「配列」に対して、使える関数、map関数は、「配列」に対して、使える関数、map関数は、「配列」に対して、使える関数...

公式:

とはいえ、今回の例のように、正直エラー内容が出る場合はあまりハマらないです。

しかし、TypeScriptで型指定していたり、別のケースの場合、素直に、オブジェクトには使えないよ、というエラーじゃない場合もあります。

こうなったものにゃ、延々泣きながら、ググり地獄コースですよね。

ただ、オブジェクトではmap関数は使えないこと、配列にしか使えないということを覚えておけば、1分で解決できるのですが。←

ケース2: useEffectの中で定義している値が、なぜか使う時にエラーを吐かれる

ReactのhooksであるuseEffectを使って、JavaScriptで取得した値で、処理を分岐させることありますよね。(リダイレクト処理とかで)

上記によって、値が入ってきたら、その値で処理を分けるみたいな。

例えば、以下のような感じで、例えば、URLを見て、リダイレクト先を変えたい場合の想定で。

test.js
//next/routerというNext.jsのhooksで、ブラウザのURLの値を色々取れます
const test1 = router.pathname.indexOf("login");
const test2 = router.pathname.indexOf("redirect");

useEffect(() => {
    if(test1 && test2) {
      //if文の条件がtrueの時だけ、何がしかの走らせたい関数
    }
    else {
      //if文の条件がtrueじゃない時、何がしかの走らせたい関数
    }
  })
},[test1,test2])

と、Reactの便利hooksやら、Next.jsのuseRouterやらを駆使して、わがもの顔で書いていると、、、

ぬ、ぬぬ!?

え、えらあ...?ぬぁあああにい!?やっちまったなぁ!?

エラー内容としては、そもそもtest1やら、test2やらの値は存在しないぜというもの。

これの理由は、シンプルで、2つ。
・useRouterの取る値は、最初はundefinedになるから(Next.js)
・上記実装だと、値がないケースでも走ってしまうから(JavaScript)

という2つの理由です。

なので、

test.js
- const isRouter = router.pathname; //router.isReadyでrouterの準備を見た方がスッキリと記述できるため、修正
const test1 = router.pathname.indexOf("login") !== -1; //loginという文字列があるかないかを、true,falseで返す
const test2 = router.pathname.indexOf("redirect") !== -1; //redirectという文字列があるかないかを、true,falseで返す

useEffect(()=>{
-    if(isRouter) { //router.isReadyでrouterの準備を見た方がスッキリと記述できるため、修正
+    if(router.isReady) { //ここがtrueになるまでは、処理をスルーさせる
      if(test1 && test2) {
        //if文の条件がtrueの時だけ、何がしかの走らせたい関数
      }
      else {
        //if文の条件がtrueじゃない時、何がしかの走らせたい関数
      }
    }
  })
},[test1,test2,router.isReady])

上記のように、isRouterの中身を見るif文を噛ませることで、準備ができた状態で、正しく条件分岐した処理が走ります。

これ、例えば、JavaScriptに関しての知識が皆無だと、延々、Reactやら、Next.jsのエラーをググりまくって、でも、結局は、JavaScriptの問題なので、延々解決しないんですよね。

やっぱり、JavaScriptのキソ、ダイジ。

あと、今回のケースはif文で、条件分けしましたが、JavaScriptの三項演算子というもので、コードをすっきりと書く方法もありますので、よろしければ、ググってみてください。(ご存じの方多いかもですが)

ケース3: APIで取得した値をわがもの顔で、mapで回したら、あっさりとガンギレされるやつ

test.js
const [posts, setPosts] = useState("");

  useEffect(() => {
    axios.get("https://jsonplaceholder.typicode.com/posts").then((res) => {
      setPosts(res.data);
    });
-  }, [posts]); //こちらは、res.dataに変化があるものである場合、無限レンダリングされる可能性ありのため、修正
+  }, []); //こちらであれば、初回レンダリング時のみ処理が走る
  return (
    <div className="App">
      {posts.map((post) => { //ここでお叱りを受ける
        return <p key={post.id}>{post.title}</p>;
      })}
    </div>
  );

なんでなの、オブジェクトはmap使えないのはさっき学んだけど、配列でもmapが使えないなんて聞いてないぜ!

むむむ〜!!

このパターンについても、基本的には、JavaScriptの知識でして。

このパターンは、APIを使用している、つまり非同期処理を行なった結果、値を取得しています。
なので、初期値、つまり、非同期処理が完了する前の値、つまり初期値は、""。
””は、空文字、つまり文字列ですね。

文字列は、map使えましたっけ?
答えはNoです。
mapは、配列のみに使用可能です。

だから、トラウマになるくらいに、怒鳴られてしまったんですねぇ〜。

今回のケースの場合は、初期値の値に変化がない場合は、条件分岐で、map処理を通さないようにしてあげるのがいいかなと。
というか、以下のように、シンプルに[]にしておけば、エラーでは怒られないですね。

test.js
const [posts, setPosts] = useState([]);

  useEffect(() => {
    axios.get("https://jsonplaceholder.typicode.com/posts").then((res) => {
      setPosts(res.data);
    });
-  }, [posts]); //こちらは、res.dataに変化があるものである場合、無限レンダリングされる可能性ありのため、修正
+  }, []); //こちらであれば、初回レンダリング時のみ処理が走る
  return (
    <div className="App">
      {posts && posts.map((post) => {
        return <p key={post.id}>{post.title}</p>;
      })}
    </div>
  );

APIは若干、想像だけだと、イメージしづらいと思うので、以下のcodesandboxでいじりつつ見れるので、よろしければ。

以上の感じで、普通に、生のJavaScriptの知識の不足がこんなエラーを引き起こしちゃうんですよね。

Reactやらの仕様なのと思いきや、もちろん、Reactなどの仕様でもつまづきますが、
・Reactもわからん
・JavaScriptもわからん
という状態だと、2倍、いや、2倍以上に苦しみますよね。

改めて、Next.jsかっけぇ!Reactが時代っしょ!とうつつを抜かす前に、ピュレ..あ、じゃなくて、ピュアなJavaScriptの基礎を学んでいただけるといいかと

確かに、遠回りだなと感じるというのも、すごくわかるんですが、なんやかんやで、Reactも、Vueも、AngularもjQueryも、全ては、生のJavaScriptありきですからね。

基礎工事を適当にやって作られたハリボテの家はすぐに、ガタガタと崩れ落ちます。

それもまた、いとをかしですが、どうせお勉強するのであれば、着実に、足元から固めて、長い間活きる力をつけていった方がコスパはいいんじゃないかなと思うんです。

時間は有限ですし。

dear 自分 (親愛なる自分へ)

コメントいただき、アドバイスくださった方、ありがとうございます。
自身、まだまだ未熟ですので、教えていただき、とても勉強になります。

63
55
12

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?