反应useState不在渲染上更新

时间:2020-09-22 18:34:21

标签: javascript reactjs

因此,我试图让getAllEvents()仅在首次呈现页面时运行,并且让getFilteredEvents()在eventFilters更新/更改时运行。我仍然希望getFilteredEvents()在页面加载时运行,以便可以将其传递到Events组件中进行渲染。

但是,仅当我使用FilterBar组件中的按钮修改eventFilters时,getFilteredEvents()才似乎运行,而不是在首次加载页面时运行。我可以通过在渲染哪个console.log()allEvents和filteredEvents之后显示一个仅填充allEvents的按钮来确认这一点。但是当我在渲染时在useEffect或getFilteredEvents中使用console.log()allEvents时,它为空。我也尝试过将getFilteredEvents()放在仅页面渲染的useEffect内,但这也不起作用。

  const [eventFilters, setEventFilters] = useState(["OTHER", "WORKSHOP", "MEAL", "SPEAKER", "MINIEVENT"]);
  const [allEvents, setAllEvents] = useState([]);
  const [filteredEvents, setFilteredEvents] = useState([]);

  const something = () => {
    console.log(allEvents);
    console.log(filteredEvents);
  }

  useEffect(() => {
    getAllEvents();
    setEventFilters(eventFilters.concat("ALL"));
  }, []);

  useEffect(() => {
    getFilteredEvents();
  }, [eventFilters]);

  const getAllEvents = async () => {
    const response = await fetch(URL);
    const data = await response.json();

    setAllEvents(data.events);
  };

  const getFilteredEvents = () => {
    console.log("getFilteredEvents has run");
    setFilteredEvents(allEvents.filter(event => {
      console.log("filteredEvents is being populated");
      if(eventFilters.includes(event.eventType)){
        return {...event}
      }
    }));
  }

 return (
    <div className="App">
      <button onClick={something}>a</button>
      <Container>
          <div>
            <h1>2021 HackIllinois Schedule</h1>
          </div>
          <div>
            <FilterBar eventFilters={eventFilters} setEventFilters={setEventFilters}/>
          </div>
        <Row>
          <Col> <AllEvents filteredEvents={filteredEvents} selectedDay={selectedDay}/> </Col>
        </Row>
      </Container>
      
     
    </div>
  )

2 个答案:

答案 0 :(得分:0)

正如@Robin突出显示的那样,您必须避免页面呈现,直到filteredEvents具有值为止。您有两个选择,要么返回一个等待的组件,要么返回null

  const [eventFilters, setEventFilters] = useState(["OTHER", "WORKSHOP", "MEAL", "SPEAKER", "MINIEVENT"]);
  const [allEvents, setAllEvents] = useState([]);
  const [filteredEvents, setFilteredEvents] = useState([]);

  const something = () => {
    console.log(allEvents);
    console.log(filteredEvents);
  }

  useEffect(() => {
    getAllEvents();
    setEventFilters(eventFilters.concat("ALL"));
  }, []);

  useEffect(() => {
    getFilteredEvents();
  }, [eventFilters]);

  const getAllEvents = async () => {
    const response = await fetch(URL);
    const data = await response.json();

    setAllEvents(data.events);
  };

  const getFilteredEvents = () => {
    console.log("getFilteredEvents has run");
    setFilteredEvents(allEvents.filter(event => {
      console.log("filteredEvents is being populated");
      if(eventFilters.includes(event.eventType)){
        return {...event}
      }
    }));
  }

if(!filteredEvents){
return null   // just giving this hint for testing, for practicle purpose don't use this. Instead render a component showing waiting state
}

 return (
    <div className="App">
      <button onClick={something}>a</button>
      <Container>
          <div>
            <h1>2021 HackIllinois Schedule</h1>
          </div>
          <div>
            <FilterBar eventFilters={eventFilters} setEventFilters={setEventFilters}/>
          </div>
        <Row>
          <Col> <AllEvents filteredEvents={filteredEvents} selectedDay={selectedDay}/> </Col>
        </Row>
      </Container>
      
     
    </div>
  )

答案 1 :(得分:0)

这可能不是一个很好的解决方案,但它确实起作用....

  useEffect(() => {
    getAllEvents();
  }, []);

  useEffect(() => {
    getFilteredEvents();
  }, [allEvents]);

  useEffect(() => {
    getFilteredEvents();
  }, [eventFilters]);

我不知道为什么这行得通,setTimeout却行不通,但现在我什至不在乎。