Как я могу заставить перезапустить ловушку реакции useEffect на основе значения переменной? - PullRequest
0 голосов
/ 16 марта 2020

Итак, я получил этот компонент:

export default function () {
    const [todos, setTodos] = useState([]);


    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, []);

    console.log(todos);

    return (
        <div>
            ...
        </div>
    );
}

Я использую хук useEffect для извлечения всех задач из базы данных, и он отлично работает. Проблема в том, что я не знаю, как использовать useEffect для запуска повторного рендеринга каждый раз, когда я делаю модификацию массива todos, например добавление, удаление или обновление. Если я добавлю массив зависимостей useEffect в переменную todos, я получу бесконечную запись l oop в консоли. Как я могу использовать useEffect для запуска рендеринга в любое время, когда массив todos обновляется?

Ответы [ 2 ]

1 голос
/ 16 марта 2020

Проблема в том, что внутри использования нет логики c. Эффект см. Ниже:

    const [todos, setTodos] = useState([]);

    useEffect(() => {
        setTodos([1])
    }, [todos])

Это также даст бесконечное значение l oop. но мы всегда даем одно и то же значение. Проблема в том, что когда он обновляется, зависимость становится истинной, поэтому он снова начинает выполнять useEffect (). Вы должны придумать какую-то конкретную логику c, например length, изменилась, или вы можете принять новое состояние, подобное приведенному ниже

    const [todos, setTodos] = useState([]);
    const [load, setLoad] = useState(false);

    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, [load])

    console.log(todos)
    return (
        <div>
            <button
            onClick={() => {
                todos.push(1)
                setLoad(!load)
            }}
            >cilck</button>
        </div>
    );
0 голосов
/ 16 марта 2020

Вы могли бы поднять состояние, выбирая задачи в родительском компоненте, а затем передавая результат в качестве реквизита дочернему компоненту, чей useEffect зависит от него. Любые операции CRUD должны быть вызваны в родительском компоненте для обновления списка (но вы можете инициировать изменения из дочерних компонентов, передавая эти функции дочернему).

В противном случае это также будет хорошо приложение для Redux. Вы сможете инициализировать компонент с помощью действия извлечения Redux, чтобы заполнить хранилище всеми операциями CRUD, выполненными для любого компонента, а также обновить хранилище через ответ API, модифицирующий редуктор. Затем вы можете использовать хранилище как зависимость useEffect для обновления локального состояния задач вашего компонента.

// State
const [todos, setTodos] = useState(null);
// Redux Stores 
const todoStore = useSelector(state => state.todoStore);
// Redux Dispatch
const dispatch = useDispatch();
// Lifecycle: initialize the component's todolist
useEffect(() => {
    if (!todos) {
        // your Redux Action to call the API fetch & modify the store
        dispatch(fetchTodos); 
    }
}, [dispatch, todos]
// Lifecycle: update the todolist based on changes in the store
// (in this case I assume the data is populated into todoStore.items)
useEffect(() => {
    if (todoStore.items.length > 0) {
        setTodos(todoStore);
    }
}, [todoStore.items]

return {
    <div>{ todos.map((todo, index) => <li key={'todo_'+index}>{todo}</li>) }</div>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...