【问题标题】:React hooks: useState not setting correctly反应钩子:useState 设置不正确
【发布时间】:2020-04-11 16:46:13
【问题描述】:

我在父组件中创建了一个 setter 函数并将其传递给它的子组件:

有问题的部分:

export default function Day({ dayInfo, props }) {
  var [timeOfDay, setTimeOfDay] = useState('');


  function TimeOfDaySetter(index) {
    console.log('index ', index);
    if (index === 0) {
      setTimeOfDay((timeOfDay) => (timeOfDay = 'AM'));
      return <Header as="h1">{timeOfDay}</Header>;
    } else if (index === 12) {
      setTimeOfDay((timeOfDay) => (timeOfDay = 'PM'));
      return <Header as="h1">{timeOfDay}</Header>;
    }
  }

该函数嵌套在子函数的 map 函数中:

     {Array.from(Array(amountOfRows)).map((row, index) => {
          return (
            <React.Fragment key={index}>
              <Table.Row>
                <Table.Cell rowSpan="2" style={tableStyle}>
                  {TimeOfDaySetter(index)}
                </Table.Cell>

但这是跳过第一个条件?

谁能帮忙解释一下为什么会这样?

完整的父级和组件:

import { Header, Table, TextArea } from 'semantic-ui-react';
import React, { useState, useEffect } from 'react';

export default function Day({ dayInfo, props }) {
  var [dayInfoInChild, setDayInfoInChild] = useState([]);
  var [timeOfDay, setTimeOfDay] = useState('');

  function setExactHourHelper(index) {
    return index === 0 ? 12 : '' || index > 12 ? index - 12 : index;
  }

  function TimeOfDaySetter(index) {
    console.log('index ', index);
    if (index === 0) {
      setTimeOfDay((timeOfDay) => (timeOfDay = 'AM'));
      return <Header as="h1">{timeOfDay}</Header>;
    } else if (index === 12) {
      setTimeOfDay((timeOfDay) => (timeOfDay = 'PM'));
      return <Header as="h1">{timeOfDay}</Header>;
    }
  }

  useEffect(() => {

    if (dayInfo !== null) {
      var modifiedDayInfo = dayInfo
        .split(' ')
        .map((item) => {
          if (item.indexOf(',')) return item.replace(/,/g, '');
        })
        .join('-');

      if (localStorage.getItem(modifiedDayInfo)) {
        // setDayInfoInChild(function (dayInfoInChild) {
        //   return [...setDayInfoInChild, modifiedDayInfo];
        // });
        console.log(modifiedDayInfo);
      } else {
        localStorage.setItem(modifiedDayInfo, JSON.stringify({}));
      }
    }
  }, [dayInfo, timeOfDay, timeOfDay]);

  function TableLayout({ TimeOfDaySetter }) {
    var [amountOfRows, setAmountOfRows] = useState(24);
    var [textValue, setTextValue] = useState('');

    function handleChange(event) {
      setDayInfoInChild(event.target.value);
    }

    const tableStyle = {
      borderLeft: 0,
      borderRight: 0,
    };

    const colorOveride = {
      color: '#C1BDBD',
    };

    return (
      <>
        <h1>{dayInfo}</h1>
        <Table celled structured>
          <Table.Body>
            {Array.from(Array(amountOfRows)).map((row, index) => {
              return (
                <React.Fragment key={index}>
                  <Table.Row>
                    <Table.Cell rowSpan="2" style={tableStyle}>
                      {TimeOfDaySetter(index)}
                    </Table.Cell>
                    <Table.Cell style={tableStyle}>
                      {
                        <strong>
                          {setExactHourHelper(index)}
                          :00
                        </strong>
                      }
                      <TextArea
                        rows={2}
                        name="textarea"
                        value={textValue}
                        onChange={handleChange}
                        placeholder="Tell us more"
                      />
                    </Table.Cell>
                  </Table.Row>
                  <Table.Row>
                    <Table.Cell style={(tableStyle, colorOveride)}>
                      {
                        <strong>
                          {setExactHourHelper(index)}
                          :30
                        </strong>
                      }
                      <TextArea rows={2} placeholder="Tell us more" />
                    </Table.Cell>
                  </Table.Row>
                </React.Fragment>
              );
            })}
          </Table.Body>
        </Table>
      </>
    );
  }

  {
    if (dayInfo === null) {
      return <p>Loading...</p>;
    }
  }

  return (
    <React.Fragment>
      <TableLayout
        dayInfo={dayInfo}
        timeOfDay={timeOfDay}
        TimeOfDaySetter={TimeOfDaySetter}
      />
    </React.Fragment>
  );
}

【问题讨论】:

  • useState 不应该是箭头函数,setTimeOfDay('AM')
  • 这段代码有很多小错误,但最大的错误是你假设setState在(TimeOfDaySetter)中是同步的,这是不正确的。
  • @DennisVash 想详细说明一下吗?我很想得到反馈!

标签: reactjs react-hooks use-state


【解决方案1】:

它应该只是 setTimeOfDay("AM") 和第二个条件块 setTimeOfDay("PM")。您通过传入一个返回字符串的函数使其过于复杂。虽然您可以传入一个返回字符串的函数,但为了让您的 setTimeOfDay 将其字符串设置为,您的函数存在一个基本问题,即您也在手动更改状态。

请注意,您的函数中有“timeOfDay = 'AM'”。这完全违背了 setState 和 useState 的目的,因为您是直接操作状态。

传统的 setState 确实有可以接受函数的用例,但我不相信 useState 可以。

// Correct
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});

反正这个功能现在对你也没用。

另外,在你的 useEffect 中。即使您的使用效果与 [dayInfo, timeOfDay, timeOfDay] 相关联,它实际上从未被修改过,至少在您显示的代码中是这样。因此,您的 Day 组件仅在挂载期间获取 dayInfo 的更改,而不是重新渲染。

另外,除非我遗漏了什么,因为当你调用时,你的状态是在你的 Day 组件中管理的,而不是每个单独的 React Fragment

{Array.from(Array(amountOfRows)).map((row, index) => {
          return (
            <React.Fragment key={index}>
              <Table.Row>
                <Table.Cell rowSpan="2" style={tableStyle}>
                  {TimeOfDaySetter(index)}
                </Table.Cell>

您只是在地图上的每次迭代中更改 Day 组件的状态,这将导致您的反应片段重新渲染。所以只有最后一个条件会被尊重,因为每个片段都会重新渲染。最好将 props 传递给一个新的组件项,而不是在每次迭代时调用 state,让你的 state 更复杂地管理每个片段,或者在每个组件中本地管理你的 state。

【讨论】:

  • 谢谢 Chris,最初 TimeOfDaySetter 只是一个对映射函数作出反应的函数 index 输入:function TimeOfDay(index) { if (index === 0) { return &lt;Header as="h1"&gt;AM&lt;/Header&gt;; } else if (index === 12) { // setTimeOfDay('PM'); return &lt;Header as="h1"&gt;PM&lt;/Header&gt;; } } 无论如何,现在我知道我应该只使用一个简单的函数。
  • 乐于助人。是的,我不确定您是否会遇到任何其他问题。但我认为删除生成的每个片段的状态设置会有所帮助。
  • 并且useState 中的依赖项只能是useEffect(() =&gt; {.....}, [dayInfo]); 非常感谢您的帮助!
【解决方案2】:

我看到你将箭头函数作为 setTimeOfDay 参数传递:

setTimeOfDay((timeOfDay) =&gt; (timeOfDay = 'AM'));

相反,您应该像通常的设置器一样调用 setTimeOfDay,即:

setTimeOfDay('AM');

【讨论】:

  • 感谢您的反馈,我很感激,但没有奏效。
  • 虽然这段代码不常见,(timeOfDay = 'AM') return AM 这是setter所期望的,但它也不能解决OP的问题
  • 您好 Dennis,这是真的,它返回一个字符串,但请注意 OP 通过调用 timeOfDay = "AM" 手动操作状态。但是,我确实相信问题的真正根源在于 map 方法和每次在 day 组件上调用 set state 以渲染更小的片段。它会导致每次对每个片段进行重新渲染,最后一个片段将是被尊重的片段。
猜你喜欢
  • 2020-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 2019-09-15
  • 2021-04-10
相关资源
最近更新 更多