구성 요소를 다시 렌더링하지 않는 UseContext 변경에 반응

새긴 ​​금

UseContext 및 UseReducer를 배우기 위해 React를 사용하여 간단한 'Nonogram'/ 'Picross'게임을 만들려고하는데, 사용하는 값이 변경 될 때 내 상위 구성 요소 (App)가 다시 렌더링되지 않는 이유에 대해 의아해합니다. 아마도 나는 기본적인 것을 놓치고 있지만 온라인에서 문서와 예제를 읽었으며 왜 다시 렌더링되지 않는지 알 수 없습니다.

예상 : 사용자가 응용 프로그램으로 이동하여 사각형을 클릭하여 값을 변경하고 (사각형을 클릭하여 십자가를 그립니다) 보드 아래의 텍스트는 'isComplete'값을 기반으로하므로 "축하합니다!"라고 표시됩니다.

문제 : 위와 같지만 '계속 시도'가 남아 있습니다.

UseReducer 함수에 정의 된대로 boardState를 볼 수있는 버튼도 추가했습니다.

코드는 다음과 같습니다.

App.js

import './App.css';
import { useReducer } from 'react';
import Table from './Table';
import BoardContext from './BoardContext';
import boardReducer from './BoardReducer';

function App() {
  //Puzzle layout
  const puzzleArray = [
    [true, false, true], 
    [false, true, false], 
    [true, false, true]
  ];

  //Creating a set of blank arrays to start the game as the userSelection
  const generateUserSelection = () => {
    const userSelection = [];
    puzzleArray.forEach(row => {
      let blankRow = [];
      row.forEach(square => {
        blankRow.push(false)
      });
      userSelection.push(blankRow);
    })
    return userSelection;
  };

  //Initial Context value
  const boardInfo = {
    puzzleName: "My Puzzle",
    puzzleArray: puzzleArray,
    userSelection: generateUserSelection(),
    isComplete: false
  };

  const [ boardState, dispatch ] = useReducer(boardReducer, boardInfo)

  return (
    <BoardContext.Provider value={{board: boardState, dispatch}}>
      <div className="App">
        <header className="App-header">
          <p>
            Picross
          </p>
          <Table />
        </header>
        <div>
          {boardState.isComplete ? 
            <div>Congratulations!</div>
          : <div>Keep trying</div>
          }
        </div>
        <button onClick={() => console.log(boardState)}>boardState</button>
      </div>
    </BoardContext.Provider>
  );
}

export default App;

Table.jsx :

import { useContext, useEffect } from 'react';
import './App.css';
import Square from './Square';
import BoardContext from './BoardContext';

function Table() {

    useEffect(() => {console.log('table useEffect')})

    const { board } = useContext(BoardContext);

    const generateTable = solution => {
        const squareLayout = []

        for (let i = 0; i < solution.length; i++) {
            const squares = []
            for (let j = 0; j < solution[i].length; j++) {
                squares.push(
                    <Square 
                        position={{row: i, column: j}}
                    />
                );
            };
            squareLayout.push(
                <div className="table-row">
                    {squares}
                </div>
            );
        };
        return squareLayout;
    };

  return (
    <div className="grid-container">
        {generateTable(board.puzzleArray)}
    </div>
  );
}

export default Table;

Square.jsx

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

function Square(props) {
  
    const { board, dispatch } = useContext(BoardContext)

    const [ isSelected, setIsSelected ] = useState(false);
    const { position } = props;

    const handleToggle = () => {
        console.log(board)
        board.userSelection[position.row][position.column] = !board.userSelection[position.row][position.column]
        dispatch(board);
        setIsSelected(!isSelected);
    }

    return (
    <div className={`square ${isSelected ? " selected" : ""}`}
        onClick={handleToggle}
    >
        {position.row}, {position.column}
    </div>
  );
}

export default Square;

감사

편집 : 나는 이와 같은 간단한 응용 프로그램의 경우 상태를 소품을 통해 전달하는 것이 매우 쉬울 것이라는 것을 알고 있지만 아이디어는 다른 후크를 연습하는 것이므로 피하고 싶습니다. 내가 여기서 실천하고있는 아이디어는 이상적으로는 미래의 더 큰 프로젝트로 확장 될 수있을 것입니다.

편집 2 : 요청에 따라 다음은 내 BoardReducer.js 파일입니다.

const boardReducer = (state, updateInfo) => {

    let isComplete = false;

    if (JSON.stringify(updateInfo.userSelection) === JSON.stringify(state.puzzleArray)) {
        isComplete = true;
    }

    updateInfo.isComplete = isComplete;
    return updateInfo;
}

export default boardReducer;

(JSON.stringify를 사용하여 일치하는 배열을 확인하는 저렴한 방법으로 지금은 작은 것입니다!)

드류리스

발행물

몇 군데에서 상태 객체를 변경합니다.

const handleToggle = () => {
  console.log(board);
  board.userSelection[position.row][position.column] = !board.userSelection[position.row][position.column]; // <-- mutation!
  dispatch(board);
  setIsSelected(!isSelected);
}

그리고 감속기에서

const boardReducer = (state, updateInfo) => {
  let isComplete = false;

  if (JSON.stringify(updateInfo.userSelection) === JSON.stringify(state.puzzleArray)) {
    isComplete = true;
  }

  updateInfo.isComplete = isComplete; // <-- mutation!
  return updateInfo; // <-- returning mutated state object
}

새로운 상태 객체가 생성되지 않기 때문에 React는 상태 변경을 보지 않고 UI를 다시 렌더링하지 않습니다.

해결책

useReducer는 일반적으로 감속기 함수는 현재 소비에 "REDUX"패턴 사용됩니다 stateaction그 상태에서 작동하고, 반환 새로운 상태 개체를.

사용자 선택을 토글하고 전체 보드를 확인하는 작업을 발송해야합니다.

보드 감속기

상태를 업데이트 할 때 전체 state개체 부터 시작하여 업데이트중인 모든 상태 개체를 새 개체 참조로 얕게 복사해야 합니다.

const boardReducer = (state, action) => {
  if (action.type === "TOGGLE") {
    const { position } = action;
    const nextState = {
      ...state,
      userSelection: state.userSelection.map((rowEl, row) =>
        row === position.row
          ? rowEl.map((colEl, col) =>
              col === position.column ? !colEl : colEl
            )
          : rowEl
      )
    };

    nextState.isComplete =
      JSON.stringify(nextState.userSelection) ===
      JSON.stringify(state.puzzleArray);

    return nextState;
  }
  return state;
};

실제로 액션 객체를 반환하는 함수 인 액션 생성자를 만듭니다.

const togglePosition = position => ({
  type: "TOGGLE",
  position
});

그런 handleToggle다음는 전달 된 작업에서 행 및 열 위치를 소비 / 전달해야합니다.

const handleToggle = () => dispatch(togglePosition(position));

간단한 데모

react-usecontext-change-not-re-rendering-component 편집

여기에 이미지 설명 입력

데모 코드 :

const puzzleArray = [
  [true, false, true],
  [false, true, false],
  [true, false, true]
];

const userSelection = Array(3).fill(Array(3).fill(false));

const togglePosition = (row, column) => ({
  type: "TOGGLE",
  position: { row, column }
});

const boardReducer = (state, action) => {
  if (action.type === "TOGGLE") {
    const { position } = action;
    const nextState = {
      ...state,
      userSelection: state.userSelection.map((rowEl, row) =>
        row === position.row
          ? rowEl.map((colEl, col) =>
              col === position.column ? !colEl : colEl
            )
          : rowEl
      )
    };

    nextState.isComplete =
      JSON.stringify(nextState.userSelection) ===
      JSON.stringify(state.puzzleArray);

    return nextState;
  }
  return state;
};

export default function App() {
  const [boardState, dispatch] = React.useReducer(boardReducer, {
    puzzleArray,
    userSelection,
    isComplete: false
  });

  const handleClick = (row, column) => () =>
    dispatch(togglePosition(row, column));

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>

      <div>{boardState.isComplete ? "Congratulations!" : "Keep Trying"}</div>

      <div>
        {boardState.userSelection.map((row, r) => (
          <div key={r}>
            {row.map((col, c) => (
              <span
                key={c}
                className={classnames("square", { active: col })}
                onClick={handleClick(r, c)}
              />
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

Redux는 상태 변경 후 구성 요소를 다시 렌더링하지 않는 반응

분류에서Dev

반응 : 컨텍스트의 변경이 내 구성 요소를 다시 렌더링하지 않습니다.

분류에서Dev

반응에서 구성 요소를 다시 렌더링하지 않는 첫 번째 클릭

분류에서Dev

속성이 변경 될 때 반응에서 특정 구성 요소를 다시 렌더링하는 방법

분류에서Dev

상태 변경 반응시 구성 요소가 다시 렌더링되지 않습니다.

분류에서Dev

반응 함수 구성 요소에서 다시 렌더링하는 논리

분류에서Dev

계층을 변경 한 후 상태를 유지하고 반응 구성 요소의 다시 렌더링을 방지하는 방법은 무엇입니까?

분류에서Dev

전체 목록을 다시 렌더링하지 않고 루프의 단일 하위 구성 요소를 변경할 수 있습니까 (반응 후크)

분류에서Dev

메모를 사용하고 소품이 변경되지 않았음에도 불구하고 기능적 구성 요소에서 자식을 다시 렌더링하는 반응

분류에서Dev

Vue.js-항상 다시 렌더링되지 않는 반응 구성 요소

분류에서Dev

상태 변경 후 다시 렌더링되지 않는 반응, 자식 구성 요소의 상태를 어떻게 설정합니까?

분류에서Dev

반응이 입력 변경시 기능 구성 요소의 모든 요소를 다시 렌더링하는 이유

분류에서Dev

동일한 유형의 여러 구성 요소가있는 반응 페이지. 버튼 클릭시 동일한 구성 요소를 더 많이 표시하고 원래 세트에서 다시 렌더링되지 않도록합니다.

분류에서Dev

라우터 변경 경로에 반응하지만 렌더링 구성 요소는 아님

분류에서Dev

상태를 변경하지 않고 구성 요소를 다시 렌더링하는 방법

분류에서Dev

다시 렌더링하지 않고보기에 반응 네이티브 구성 요소를 추가하려면 어떻게해야합니까?

분류에서Dev

반응 네이티브에서 예상대로 이미지를 렌더링하지 않는 구성 요소

분류에서Dev

렌더링되지 않는 하위 구성 요소-반응

분류에서Dev

React Router는 링크를 변경하지만 적절한 구성 요소를 렌더링하지 않습니다.

분류에서Dev

ReactJS에서 전체 트리를 다시 렌더링하지 않고 트리 구성 요소의 리프 구성 요소를 렌더링하는 방법

분류에서Dev

도구 없이는 작동하지 않는 다른 구성 요소 가져 오기 및 렌더링 반응

분류에서Dev

반응 / 반응 후크 : 상태가 변경된 후 자식 구성 요소가 다시 렌더링되지 않습니까?

분류에서Dev

내 반응 구성 요소를 렌더링하지 않는 Express 앱

분류에서Dev

React-다시 렌더링 한 후 Google지도 구성 요소가지도를 변경하지 않음

분류에서Dev

@action 데코레이터를 반응 이벤트 핸들러 함수에 추가 할 때 구성 요소가 다시 렌더링되지 않는 이유

분류에서Dev

상태가 변경 될 때 반응 구성 요소의 입력 요소 값이 다시 렌더링되지 않습니다.

분류에서Dev

reactjs-상태 변경은 구성 요소를 다시 렌더링하지 않습니다.

분류에서Dev

반응에서 기본 구성 요소를 렌더링하는 방법

분류에서Dev

하위 구성 요소가 업데이트 될 때 반응이 다시 렌더링되지 않음

Related 관련 기사

  1. 1

    Redux는 상태 변경 후 구성 요소를 다시 렌더링하지 않는 반응

  2. 2

    반응 : 컨텍스트의 변경이 내 구성 요소를 다시 렌더링하지 않습니다.

  3. 3

    반응에서 구성 요소를 다시 렌더링하지 않는 첫 번째 클릭

  4. 4

    속성이 변경 될 때 반응에서 특정 구성 요소를 다시 렌더링하는 방법

  5. 5

    상태 변경 반응시 구성 요소가 다시 렌더링되지 않습니다.

  6. 6

    반응 함수 구성 요소에서 다시 렌더링하는 논리

  7. 7

    계층을 변경 한 후 상태를 유지하고 반응 구성 요소의 다시 렌더링을 방지하는 방법은 무엇입니까?

  8. 8

    전체 목록을 다시 렌더링하지 않고 루프의 단일 하위 구성 요소를 변경할 수 있습니까 (반응 후크)

  9. 9

    메모를 사용하고 소품이 변경되지 않았음에도 불구하고 기능적 구성 요소에서 자식을 다시 렌더링하는 반응

  10. 10

    Vue.js-항상 다시 렌더링되지 않는 반응 구성 요소

  11. 11

    상태 변경 후 다시 렌더링되지 않는 반응, 자식 구성 요소의 상태를 어떻게 설정합니까?

  12. 12

    반응이 입력 변경시 기능 구성 요소의 모든 요소를 다시 렌더링하는 이유

  13. 13

    동일한 유형의 여러 구성 요소가있는 반응 페이지. 버튼 클릭시 동일한 구성 요소를 더 많이 표시하고 원래 세트에서 다시 렌더링되지 않도록합니다.

  14. 14

    라우터 변경 경로에 반응하지만 렌더링 구성 요소는 아님

  15. 15

    상태를 변경하지 않고 구성 요소를 다시 렌더링하는 방법

  16. 16

    다시 렌더링하지 않고보기에 반응 네이티브 구성 요소를 추가하려면 어떻게해야합니까?

  17. 17

    반응 네이티브에서 예상대로 이미지를 렌더링하지 않는 구성 요소

  18. 18

    렌더링되지 않는 하위 구성 요소-반응

  19. 19

    React Router는 링크를 변경하지만 적절한 구성 요소를 렌더링하지 않습니다.

  20. 20

    ReactJS에서 전체 트리를 다시 렌더링하지 않고 트리 구성 요소의 리프 구성 요소를 렌더링하는 방법

  21. 21

    도구 없이는 작동하지 않는 다른 구성 요소 가져 오기 및 렌더링 반응

  22. 22

    반응 / 반응 후크 : 상태가 변경된 후 자식 구성 요소가 다시 렌더링되지 않습니까?

  23. 23

    내 반응 구성 요소를 렌더링하지 않는 Express 앱

  24. 24

    React-다시 렌더링 한 후 Google지도 구성 요소가지도를 변경하지 않음

  25. 25

    @action 데코레이터를 반응 이벤트 핸들러 함수에 추가 할 때 구성 요소가 다시 렌더링되지 않는 이유

  26. 26

    상태가 변경 될 때 반응 구성 요소의 입력 요소 값이 다시 렌더링되지 않습니다.

  27. 27

    reactjs-상태 변경은 구성 요소를 다시 렌더링하지 않습니다.

  28. 28

    반응에서 기본 구성 요소를 렌더링하는 방법

  29. 29

    하위 구성 요소가 업데이트 될 때 반응이 다시 렌더링되지 않음

뜨겁다태그

보관