Open17

React学習

shusukeshusuke

React HooksのsetState等があることでclass componentを使う必要がなくなった。
functional component ベースでつくることができる。

shusukeshusuke

useState(オブジェクト)

const [product, setProduct] = useState({
    name: "",
    price: "",
  });

を上記のように定義したとき、このオブジェクトのひとつの要素のみを更新するには、このようにする。

onChange={(evt) => setProduct({ ...product, name: evt.target.value })}

...productがないと、name以外の要素(今回の場合price)をnull?(とりあえずなし)に初期化してしまう。

shusukeshusuke

同じ関数内でsetCountを二度呼び出すには以下のようにする。セットした値が更新されないのは、setStateで値が更新されるのは関数が呼び出された後だから。

<button
        onClick={() => {
          setCount((prevCount) => prevCount + 1);
          setCount((prevCount) => prevCount + 1);
        }}
>

参考
https://zenn.dev/syu/articles/3c4aa813b57b8c

shusukeshusuke

useEffect

  useEffect(() => {
    console.log("useEffect invoked");
    return () => {
      //   cleanup;
    };
  }, []);

第二引数が...

  • []だと一回だけ実行
  • なにもないと、画面更新のたびに実行
  • []のなかにstateの名前を入れれば、それが更新された時にのみ実行

// cleanupの場所でそのコンポーネントが破棄されたときの処理を書く

shusukeshusuke

displayステートによって表示を変える

 {display && <Component /> }
shusukeshusuke

api叩く

axiosをインストール

npm install axios

インポート

import axios from "axios";

初回にゲット

useEffect(() => {
    axios.get("https://jsonplaceholder.typicode.com/posts").then((res) => {
      setPosts(res.data);
    });
    // return () => {
    //     cleanup
    // }
  }, []);

普通に生のjsのfetchでもできる。

useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts", {method: "GET"}).then(res => res.json()).then(data => {
        setPosts(data);
    })
  }, []);
shusukeshusuke

idを指定して、要素を取得する。idを用意して、fetchに埋め込む。

  const [id, setId] = useState(1);
fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, { method: "GET" })
      .then((res) => res.json())
      .then((data) => {
        setPosts(data);
      });
shusukeshusuke

React HooksのuseContextを使うと親から孫に簡単に値を渡せる。

shusukeshusuke

useReducer

ちょい微妙。dispatchってのを実行するとreducerの関数が実行される。countに状態が入っている。うん、理解。

import React, { useReducer } from "react";

const initialState = 0;
const reducer = (currentState, action) => {
  switch (action) {
    case "add":
      return currentState + 1;
    case "multiple":
      return currentState * 2;
    case "reset":
      return initialState;
    default:
      return currentState;
  }
};

const BasicReducer = () => {
  const [count, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <div>Count {count} </div>
      <button onClick={() => dispatch("add")}>+ 1</button>
      <button onClick={() => dispatch("multiple")}>multiple * 3</button>
      <button onClick={() => dispatch("reset")}>reset</button>
    </div>
  );
};

shusukeshusuke

useReducer単体だと、そのコンポーネントの中でしか使えない...

そこで「useContext」。

useReducer + useContext。これでRedux的なグローバルな状態管理ができる。

shusukeshusuke

useMemo

計算時間を最適化できる

関数だったisOddをuseMemo()の第一引数にしてあげるだけ。第二引数に変化がトリガーとなる値を指定する。今回の場合はcount。

const isOdd = useMemo(() => {
    let i = 0;
    //クソおそ処理
    while (i < 500000000) i++;
    return count % 2 !== 0;
  }, [count]);
shusukeshusuke

useCallback

React.memo

export default React.memo(aDisplay);

useCallbackの第二引数を[]にすることで初回だけのレンダリングに最適化できる。

const testFunction = useCallback(() => {
 
    setCount((prev) => prev + 1);
 
}, []);

Reactにおいてのパフォーマンスの向上とは、不要なレンダリングを防ぐことを意味する。

shusukeshusuke

Reactエラー

Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead.
下記の({ name, count }) を{}で囲み忘れると出る。

const aDisplay = ({ name, id }) => {
  console.log(`display${name} `);
  return <div>{id}</div>;
};

ここにまとまっているエラーのひとつ。
https://kiotera-tech.com/react_beginers_errors

shusukeshusuke

combineReducers
reducerをひとまとめにできる

const rootReducer = combineReducers({
  reducer1,
  reducer2,
});
shusukeshusuke

ReactでREST API

Get

const getTask = () => {
    axios
      .get(`http://127.0.0.1:8000/api/tasks/${id}/`, {
        headers: {
          Authorization: "Token XXXXXXXXX",
        },
      })
      .then((res) => {
        setStateSomething(res.data);
      });
  };

Delete

const deleteTask = () => {
    axios
      .delete(`http://127.0.0.1:8000/api/tasks/${id}/`, {
        headers: {
          Authorization: "Token XXXXXXXXX",
        },
      })
      .then((res) => {
        console.log(res)
      });
  };

new(post)

  const newTask = (task) => {

//ここで新たに追加するデータを用意する
    const data = {
      title: task.title,
    };
//第二引数でdataを渡す
    axios
      .post(`http://127.0.0.1:8000/api/tasks/`, data, {
        headers: {
          "Content-Type": "application/json",
          Authorization: "Token XXXXXXXXX",
        },
      })
      .then((res) => {
        setTasks([...tasks, res.data]);
        setEditedTask({ id: "", title: "" });
      });
  };

edit(put)

const editTask = (task) => {
    axios
      .put(`http://127.0.0.1:8000/api/tasks/${task.id}/`, task, {
        headers: {
          "Content-Type": "application/json",
          Authorization: "Token XXXXXXXXX",
        },
      })
      .then((res) => {
        setTasks(
          tasks.map((task) => (task.id === editedTask.id ? res.data : task))
        );
        setEditedTask({ id: "", title: "" });
      });
  };
shusukeshusuke

inputで入力できないないなと思ったら、setStateSomething()がうまくいってない!