React Hook: функция set useState не запускает повторную визуализацию - PullRequest
0 голосов
/ 07 марта 2020

В настоящее время я работаю над упрощенным проектом клона Trello. Я определил boardList с помощью useState и реализовал две функции create() и remove(), которые могут добавлять или удалять доски, списки или карты. Все отлично работает, кроме удаления списка.

Когда я нажимаю кнопку, чтобы удалить список, компонент не рендерится мгновенно. Удаление доски и карты дают мгновенные изменения. Как и в случае списков, он, похоже, не рендерится заново, хотя boardList был изменен для удаления списка. Изменения применяются, когда я go захожу на домашнюю страницу и возвращаюсь. Мне любопытно, почему setBoardList() не запускает рендер, только в этой конкретной c ситуации. Мои функции всегда предоставляют новый объект newBoardList, поэтому, вероятно, речь не идет о возврате того же объекта, который реагирующая сторона не может распознать.

Ниже мои App.js и Board.js. На маршруте Home отображаются доски, и пользователи могут щелкнуть любую из них, чтобы go ввести маршрут BoardPage, и изменить списки и карточки на доске. Board.js включает deleteList(), который связан с проблемой.

Полный проект можно посмотреть здесь: https://codesandbox.io/s/upbeat-lederberg-l3e3e

Приложение. js

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';
import { createGlobalStyle } from "styled-components";
import Home from './routes/Home';
import BoardPage from './routes/BoardPage';

const GlobalStyle = createGlobalStyle`
    body{
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        font-family: 'Montserrat';
    }
`;

export const EMPTY =  '-';

function App() {
    const [boardList, setBoardList] = React.useState([]);
    const create = (boardKey, listKey, text) => {
      if(boardKey===EMPTY){ //createBoard
        const check = boardList.filter(board => board.boardName === text);
        if(!check.length && text.length){
            const newBoardList = boardList.concat([{boardKey: text.concat(Date.now()), boardName: text, listList: []}]);
            setBoardList(newBoardList);
        } 
      }
      else if(listKey===EMPTY){ //createList
        const newBoardList = [...boardList];
        newBoardList.forEach(board => {
          if(board.boardKey===boardKey){
            const check = board.listList.filter(list => list.listName === text);
            if(!check.length && text.length){
              board.listList.push({listKey: text.concat(Date.now()), listName: text, cardList: []});
            }
          }
        });
        setBoardList(newBoardList);
      }
      else{ //createCard
        const newBoardList = [...boardList];
        newBoardList.forEach(board => {
          if(board.boardKey===boardKey){
            board.listList.forEach(list => {
              if(list.listKey===listKey){
                const check = list.cardList.filter(card => card.content === text);
                if(!check.length && text.length){
                  list.cardList.push({cardKey: text.concat(Date.now()), content: text});
                }
              }
            });
          }
        });
        setBoardList(newBoardList);
      } 
    };


    const remove = (boardKey, listKey, cardKey) => {
      if(boardKey===EMPTY){
        return;
      }
      else{
        if(listKey===EMPTY){ //removeBoard
          const newBoardList = boardList.filter(board => board.boardKey !== boardKey);
          setBoardList(newBoardList);   
        }
        else if(cardKey===EMPTY){ //removeList
          const newBoardList = [...boardList];
          newBoardList.forEach(board => {
            if(board.boardKey===boardKey){
              board.listList = board.listList.filter(list => list.listKey !== listKey);
            }
          });
          setBoardList(newBoardList);
        }
        else{ //removeCard
          const newBoardList = [...boardList];
          newBoardList.forEach(board => {
            if(board.boardKey===boardKey){
              board.listList.forEach(list => {
                if(list.listKey===listKey){
                  list.cardList = list.cardList.filter(card => card.cardKey !== cardKey);
                }
              });
            }
          });
          setBoardList(newBoardList);
        }
      }
    };
    return (
        <>
            <GlobalStyle />
            <HashRouter>
              <Route path="/" exact={true} render={props => <Home {...props} boardList={boardList} create={create} remove={remove}/>} />
              <Route path="/board/:boardName" render={props => <BoardPage {...props} create={create} remove={remove} />} />
            </HashRouter>
        </>
    );
}

export default App;

Доска. js

import React, { useState } from 'react';
import styled from 'styled-components';
import List from './List';
import {EMPTY} from '../App';

export default function Board({boardKey, boardName, listList, create, remove}) {
    const [text, setText] = useState("");
    const createNewList = text => {
        create(boardKey, EMPTY, text);
    };
    const deleteList = (key) => {
        remove(boardKey, key, EMPTY);
    };
    const onChange = e =>{
        setText(e.target.value);
    };
    const onSubmit = e => {
        e.preventDefault();
        createNewList(text);
        setText("");
    };
    return(
        <BoardContainer>
            <h4>{boardName}</h4>
            {listList.map(list => (
                <span key={list.listKey}>
                    <List boardKey={boardKey} listKey={list.listKey} listName={list.listName} cardList={list.cardList} create={create} remove={remove} />
                    <button onClick={()=>deleteList(list.listKey)}>DelL</button>
                </span>
            ))}
            <ListAdder>
                <input type="text" value={text} onChange={onChange} />
                <button onClick={onSubmit}>AddL</button>
            </ListAdder>
        </BoardContainer>
    );

}

const BoardContainer = styled.div`
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: flex-start;
`;

const ListAdder = styled.div`
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    border: 1px solid gray;
`;

1 Ответ

0 голосов
/ 07 марта 2020

Проблема в том, что вы храните состояние в двух отдельных местах, что делает его несовместимым. Вы передаете board.listList как состояние местоположения в компоненте Home, и эта ссылка не будет отслеживать изменения boardList в App.

Я привел здесь пример, который, кажется, работать по назначению: https://codesandbox.io/s/sharp-mclaren-pv2s2?fontsize=14&hidenavigation=1&theme=dark

В коде, который я связал, мы больше не передаем список в состоянии местоположения, а передаем boardList в BoardPage и извлекаем правильная доска оттуда на основе boardKey. Это позволяет нам всегда получать доступ к текущему состоянию.

Конечно, есть несколько способов сделать это, и вы можете предпочесть стиль, отличный от моего примера. Просто убедитесь, что передали фактическое состояние, а не создавайте отдельную ссылку на него.

...