web-dev-qa-db-ja.com

Reactフック付きのコンテキストは再レンダリングを防ぎます

私はReactコンテキストをフック付きのコンテキストとして使用し、私のReact app。

Reactコンポーネントが再レンダリングされないようにする方法はありますか?

ストア構成:

import React, { useReducer } from "react";
import rootReducer from "./reducers/rootReducer";

export const ApiContext = React.createContext();

export const Provider = ({ children }) => {
  const [state, dispatch] = useReducer(rootReducer, {});

  return (
    <ApiContext.Provider value={{ ...state, dispatch }}>
      {children}
    </ApiContext.Provider>
  );
};

減速機の例:

import * as types from "./../actionTypes";

const initialState = {
  fetchedBooks: null
};

const bookReducer = (state = initialState, action) => {
  switch (action.type) {
    case types.GET_BOOKS:
      return { ...state, fetchedBooks: action.payload };

    default:
      return state;
  }
};

export default bookReducer;

ルートリデューサー。可能な限り多くのリデューサーを組み合わせることができます。

import userReducer from "./userReducer";
import bookReducer from "./bookReducer";

const rootReducer = ({ users, books }, action) => ({
  users: userReducer(users, action),
  books: bookReducer(books, action)
});

アクションの例:

import * as types from "../actionTypes";

export const getBooks = async dispatch => {
  const response = await fetch("https://jsonplaceholder.typicode.com/todos/1", {
    method: "GET"
  });

  const payload = await response.json();

  dispatch({
    type: types.GET_BOOKS,
    payload
  });
};
export default rootReducer;

そして、これが本のコンポーネントです:

import React, { useContext, useEffect } from "react";
import { ApiContext } from "../../store/StoreProvider";
import { getBooks } from "../../store/actions/bookActions";

const Books = () => {
  const { dispatch, books } = useContext(ApiContext);
  const contextValue = useContext(ApiContext);

  useEffect(() => {
    setTimeout(() => {
      getBooks(dispatch);
    }, 1000);
  }, [dispatch]);

  console.log(contextValue);

  return (
    <ApiContext.Consumer>
      {value =>
        value.books ? (
          <div>
            {value.books &&
              value.books.fetchedBooks &&
              value.books.fetchedBooks.title}
          </div>
        ) : (
          <div>Loading...</div>
        )
      }
    </ApiContext.Consumer>
  );
};

export default Books;

Booksコンポーネントの値が変更されると、別のmyコンポーネントのユーザーが再レンダリングします。

import React, { useContext, useEffect } from "react";
import { ApiContext } from "../../store/StoreProvider";
import { getUsers } from "../../store/actions/userActions";

const Users = () => {
  const { dispatch, users } = useContext(ApiContext);
  const contextValue = useContext(ApiContext);

  useEffect(() => {
    getUsers(true, dispatch);
  }, [dispatch]);

  console.log(contextValue, "Value from store");

  return <div>Users</div>;
};

export default Users;

コンテキストの再レンダリングを最適化する最良の方法は何ですか?前もって感謝します!

5
lecham

私は役立つさまざまな例の希望で説明しようとしました。

コンテキストは参照IDを使用していつ再レンダリングするかを決定するため、プロバイダーの親が再レンダリングすると、コンシューマーで意図しないレンダリングがトリガーされる可能性があります。

たとえば、次のコードでは、valueの新しいオブジェクトが常に作成されるため、プロバイダーが再レンダリングするたびにすべてのコンシューマーが再レンダリングされます。

class App extends React.Component {
  render() {
   return (
      <Provider value={{something: 'something'}}>
        <Toolbar />
      </Provider>
    );
 }
}

これを回避するには、値を親の状態に引き上げます

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}
0
AviatorX

このソリューションは、コンポーネントがReactはshouldComponentUpdateと呼ばれる)でレンダリングされないようにするために使用されます。これは、Reactクラスコンポーネントで使用できるライフサイクルメソッドです。以前のように機能的なステートレスコンポーネントとして正方形:

const Square = ({ number }) => <Item>{number * number}</Item>;

あなたはcomponentShouldUpdateメソッドでクラスコンポーネントを使うことができます:

class Square extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    ...
  }

  render() {
    return <Item>{this.props.number * this.props.number}</Item>;
  }
}

ご覧のとおり、shouldComponentUpdateクラスメソッドは、コンポーネントの再レンダリングを実行する前に、次のプロパティと状態にアクセスできます。ここで、このメソッドからfalseを返すことにより、再レンダリングを防ぐことができます。 trueを返すと、コンポーネントは再レンダリングされます。

class Square extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.number === nextProps.number) {
      return false;
    } else {
      return true;
    }
  }

  render() {
    return <Item>{this.props.number * this.props.number}</Item>;
  }
}

この場合、着信番号プロップが変更されていなければ、コンポーネントは更新されません。コンポーネントにコンソールログを再度追加して、自分で試してください。 Squareコンポーネントは、パースペクティブが変更されても再レンダリングされません。 Reactアプリケーションのパフォーマンスが大幅に向上します。すべての子コンポーネントは、親コンポーネントのすべての再レンダリングで再レンダリングされないためです。最後に、コンポーネントの再レンダリングを防ぐのはユーザー次第です。

このcomponentShouldUpdateメソッドを理解することはきっとあなたを助けるでしょう!

0
Tushar Sahu