【问题标题】:React update state with button click using useState使用 useState 通过单击按钮来响应更新状态
【发布时间】:2019-09-06 04:57:27
【问题描述】:

谁能向我解释一下解决以下问题的“正确”方法是什么。我有这个包含事件数据的简单页面。最初这是上周的数据,但页面上有一个按钮可以将数据设置为全部。我使用 useEffect() 来 loadData() 并最初设置 all=false。当我单击按钮时,我想将 all 更新为 true 并将 data 更新为所有数据。

下面的代码可以工作,但有点奇怪,因为我首先必须获取 !all 的数据,然后我设置 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>

}

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案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>
    
    }
    

    在任何情况下,您的代码都会呈现两次,因为数据是异步可用的。为了改善用户体验,您可以在获取数据时显示加载器。

    【讨论】:

    • 我在问自己为什么我没有想出这个。谢谢你。这也是你会做的方式吗?我喜欢漂亮的代码,但在反应中我似乎无法找到漂亮的代码。
    • 我肯定会以上述方式进行。好的代码也伴随着实践,我相信你会变得更好
    • 谢谢。我不能赞成你的回答,因为我的声誉仍然太低 :) 记录在案:伙计们,这就是答案 :)
    • 没有问题,但是您仍然可以使用投票下方的绿色标记将答案标记为已接受
    【解决方案2】:

    您可以在按钮的onClick 上尝试类似的操作:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-22
      • 2022-12-12
      • 1970-01-01
      • 2021-06-12
      • 2018-06-28
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      相关资源
      最近更新 更多