Реагируйте на обновление состояния нажатием кнопки с помощью useState

#reactjs #react-hooks

#reactjs #реагирует на перехваты

Вопрос:

Кто-нибудь может объяснить мне, какой «правильный» способ решить указанную ниже проблему. У меня есть эта простая страница, на которой есть данные о событиях. Изначально это данные за последнюю неделю, но на странице есть кнопка, которая устанавливает данные для всех. Я использую useEffect() для загрузки данных () с первоначальным значением all=false. Когда я нажимаю кнопку, я хочу обновить все до true и данные для всех данных.

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

Есть ли хороший способ сделать это? Я попытался ввести код «onClick» наоборот, так: setAll(!all);loadData (all), но это не работает, потому что состояние не обновляется немедленно.

Любая помощь / советы были бы замечательными!!

  const Events = ({auth}) => {


const [data, setEventData] = useState([])
const [all, setAll] = useState(false)

const loadData = async (givenScope) => {
    const scope = (givenScope ? '' : '?scope=last_week')
    const eventdata = await makeAPICall('/api/events'   scope, 'GET', null, await auth.getAccessToken())
    setEventData(eventdata);
}

useEffect(() => {
    loadData(all);
}, [])

const columns = [{
    Header: 'Datum/tijd',
    accessor: 'datetime',
    Cell: props => <Moment date={props.value} tz="Europe/Amsterdam" format="YYYY-MM-DD HH:mm"/>
}, {
    Header: 'Event',
    accessor: 'value',
}]        

return <div><Button onClick={() => {loadData(!all);setAll(!all)}}>{all ? 'Last week' : 'All'}</Button> <DefaultTable data={data} columns={columns} loading={data.length > 0 ? false : true} /></div>

}
 

Ответ №1:

Относительно простым способом обработки приведенного выше кода было бы передать all значение в массив зависимостей useEffect , чтобы вы не беспокоились о loadData выполнении после обновления состояния

 const Events = ({auth}) => {

    const [data, setEventData] = useState([])
    const [all, setAll] = useState(false)

    const loadData = async (givenScope) => {
        const scope = (givenScope ? '' : '?scope=last_week')
        const eventdata = await makeAPICall('/api/events'   scope, 'GET', null, await auth.getAccessToken())
        setEventData(eventdata);
    }

    useEffect(() => {
        loadData(all);
    }, [all])

    const columns = [{
        Header: 'Datum/tijd',
        accessor: 'datetime',
        Cell: props => <Moment date={props.value} tz="Europe/Amsterdam" format="YYYY-MM-DD HH:mm"/>
    }, {
        Header: 'Event',
        accessor: 'value',
    }]        

    return <div><Button onClick={() => {setAll(all => !all)}}>{all ? 'Last week' : 'All'}</Button> <DefaultTable data={data} columns={columns} loading={data.length > 0 ? false : true} /></div>

}
 

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

Комментарии:

1. Я спрашиваю себя, почему я не придумал это. Спасибо. Это тоже так, как вы бы это сделали? Я люблю красивый код, но в react я, похоже, не могу найти свой путь к красивому коду.

2. Я бы определенно сделал это вышеуказанным образом. Также хороший код приходит с практикой, и я уверен, что вы станете лучше в этом

3. Спасибо. Я не могу поддержать ваш ответ, потому что моя репутация все еще слишком низкая 🙂 для справки: РЕБЯТА, ЭТО ОТВЕТ 🙂

4. Никаких проблем, однако вы все равно можете пометить ответ как принятый, используя зеленую метку, которая появляется под голосами

Ответ №2:

Вы можете попробовать что-то подобное на вашей кнопке onClick :

 <Button 
  onClick={ () => {
    setAll((prevState) => {
      loadData(!prevState);    // This will load the data during the state update
      return !prevState;
    }
  }}
/>