【问题标题】:State use as props in component, state change will not re-render the componentstate 用作组件中的 props,状态更改不会重新渲染组件
【发布时间】:2021-04-26 17:40:58
【问题描述】:

如果状态改变,React 会重新渲染。那为什么下面的情况不能重新渲染呢?

根据程序行为,我发现

  1. 当状态改变时,如果该状态直接在组件中使用,会重新渲染。
  2. 当状态发生变化时,如果状态被用作子组件中的道具,它不会被重新渲染。
  3. 如何直接重新渲染该子组件?

以下程序来自我的代码并进行了一些修改。 更新: SandBox 这是我在沙盒中创建的代码,我尝试模拟我的真实情况

function List(props) {

    const [fullListValue, setFullListValue] = useState([]); //store data which get from server
    const [dropDrowList, setDropDrowList] = useState([]); //store data column value (e.g. data contain "fruit" column, this state will store "apple", "berry", "banana" etc.)

    const setAllList = (data) => {
        setFullListValue(data);
    };
    useEffect ( ()=> {
      //axios call server, use setAllList(data) to save state
    ,[]}

    //when fullListValue is updated, 
    useEffect(() => {
        const dropDrowListCopy = [{ ['label']: 'ALL', ['value']: 'ALL' }];
        //push all "fruit" data in dropDrowListCopy without duplicate
        console.log(dropDrowListCopy); //this will show all dropdown I want, i.e. "ALL","apple", "berry", "banana"
        setDropDrowList(dropDrowListCopy); //set to dropDrowList, and I expect this step will re-render the SelectionList component, however, it do not
    }, [fullListValue]);

    return (
        <div>
            <div>
                {dropDrowList.length <= 1 ? (
                    'loading'  //I add this to re-render the component, but I think this is not a good way to re-render the component
                ) : ( 
                    <SelectionList
                        itemList={dropDrowList}
                    />
                )}
            </div>
        </div>
    );
}

【问题讨论】:

  • 请在Minimal, Complete, and Reproducible 代码示例中包含所有相关代码。你能分享SectionList代码吗?也许还有一个更准确的例子来说明你如何更新状态。
  • codesandbox.io/s/0wff7 这是我在沙箱中创建的代码,我尝试模拟我的真实情况

标签: reactjs components state


【解决方案1】:

问题

SecitonList 中,您将传递的道具存储到状态中,但不会在道具更改时更新状态,从而使您处于陈旧状态。出于这个原因,将 props 存储在本地组件状态中实际上是一种 React 反模式。

解决方案

props 改变时更新状态。

function SelectionList(props) {
  const [listItem, setListItem] = useState(
    props.itemList ? props.itemList : []
  );

  useEffect(() => {
    setListItem(props.itemList);
  },
  [props.itemList]);

  return (
    <FormControl>
      <Select
        renderValue={
          props.multiple ? (selected) => fieldDisplay(selected) : null
        }
        input={<Input />}
      >
        {listItem.map((item) => (
          <MenuItem key={item.value} value={item}>
            {props.multiple ? (
              <Checkbox checked={selectedValue.indexOf(item) > -1} />
            ) : null}
            <ListItemText primary={item.label} />
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

解决办法——直接消耗道具

function SelectionList(props) {
  return (
    <FormControl>
      <Select
        renderValue={
          props.multiple ? (selected) => fieldDisplay(selected) : null
        }
        input={<Input />}
      >
        {props.itemList.map((item) => (
          <MenuItem key={item.value} value={item}>
            {props.multiple ? (
              <Checkbox checked={selectedValue.indexOf(item) > -1} />
            ) : null}
            <ListItemText primary={item.label} />
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

【讨论】:

  • 谢谢!换句话说,我只更新父组件中的状态,但在子组件中,状态(从父组件传递)没有更新。于是,bug就出来了。我的理解正确吗?
  • @0o0SkY0o0 或多或少,是的,没错。
【解决方案2】:

你需要改变这个条件:

dropDrowList.length <= 1

您只为 dropDrowList 分配了 1 个对象,因此它不会呈现 SelectionList。

改为:

dropDrowList.length < 1

应该启用 SelectionList 来呈现。

【讨论】:

  • dropDrowList.length
  • @0o0SkY0o0 然后在您的 useEffect() (或其他地方)中添加另一个项目,否则由于该条件,它将永远不会呈现。
  • 建议:在 useEfect 中分配数组以具有 2 个值: const dropDrowList = [{label: 'ALL', value: 'ALL'},{label: 'Test', value:'Test' }];这将允许 SelectionList 呈现。
猜你喜欢
  • 2019-06-29
  • 2019-10-06
  • 2019-02-27
  • 1970-01-01
  • 1970-01-01
  • 2019-06-17
  • 2018-03-17
相关资源
最近更新 更多