【问题标题】:React tri-state checkbox indeterminate null error反应三态复选框不确定的空错误
【发布时间】:2021-01-22 17:28:11
【问题描述】:

我正在尝试实现一个三态复选框来做出反应。重复单击复选框将像这样循环通过blank->checked->crossed->blank->...。环顾四周并寻找答案,我找到了一个参考:Indeterminate checkbox in React JSX

我尝试过这样的事情:

export default function App() {
  const [state, setState] = React.useState({
    data: [
      {
        id: "1",
        one: 0
      },
      {
        id: "2",
        one: 0
      }
    ]
  });
  const indetSetter = React.useCallback(
    (el, id) => {

      if (el) {
        if (el.id === id && state.data.map((datum) => datum.one === 2)) {
          el.indeterminate = true;
        }
      }
    },
    [state]
  );

  const advance = (id, e) => {
    setState((state) => {
      
      state.data.map((datum) =>
        datum.id === id ? { ...datum, one: (datum.one + 1) % 3 } : { ...datum }
      );
    });

  return (
    <>
      {state.data.map((item) => {
        // console.log("show", item);
        return (
          <input
            key={item.id}
            id={item.id}
            type="checkbox"
            checked={item.one === 1}
            ref={(el) => indetSetter(el, item.id)}
            onChange={(e) => advance(item.id, e)}
          />
        );
      })}
    </>
  );
}

但最终它会抛出一个错误:can't access property "indeterminate", el is nullcan't access property "data", state is undefined

工作sn-p:https://codesandbox.io/s/relaxed-hill-qqb4y

非常感谢任何解决此问题的帮助。

提前致谢:)

【问题讨论】:

  • 尝试使用useLayoutEffect,以便在dom可用后执行代码
  • @diedu 我不确定我正在尝试执行的代码。使用useLayoutEffect 会补充我写的逻辑吗?如果你能帮上忙
  • 对不起,我的评论是完全错误的,你没有使用任何useEffect 钩子。更详细地看一下,我认为您应该创建一个单独的组件来封装不确定复选框的逻辑。顺便说一句,codesandbox 与问题中的代码非常不同

标签: html reactjs checkbox refs


【解决方案1】:

正如我所评论的,您需要将不确定的逻辑封装在一个单独的组件中,以便能够在通过 useEffect 更改值时更新 dom,正如 here 所解释的那样

这是单个不确定复选框的组件

IndeterminateInput.js

import React, { useCallback, useEffect, useRef } from 'react';

export default function IndeterminateInput({ id, name, value, onChange }) {
  const el = useRef(null);

  const onChangeHandler = useCallback(
    event => {
      onChange({ id, name, value: (value + 1) % 3 });
    },
    [id, name, value, onChange],
  );

  useEffect(() => {
    el.current.checked = value === 1;
    el.current.indeterminate = value === 2;
  }, [value]);

  return (
    <input type="checkbox" name={name} ref={el} onChange={onChangeHandler} />
  );
}

然后你为你的主要组件中的每个项目渲染一个IndeterminateInput,并传递必要的道具

export default function App() {
  const [state, setState] = ...

  const onChange = useCallback((item) => {
    const { id, value } = item;
    setState((prevState) => {
      return {
        data: prevState.data.map((datum) => {
          return id === datum.id
            ? {
                ...datum,
                one: value
              }
            : datum;
        })
      };
    });
  }, []);

  return (
    <>
      {state.data.map((item, i) => {
        return (
          <IndeterminateInput
            key={item.id}
            id={item.id}
            name={item.name}
            value={item.one}
            onChange={onChange}
          />
        );
      })}
    </>
  );
}

你可以在这里看到它:https://codesandbox.io/s/stoic-euler-e97so?file=/src/App.js

【讨论】:

  • 谢谢。我只需要问一件事。如果我们有多个元素需要引用,我们不需要为多个元素创建动态 refs() 吗? DOM 会自动检测每个当前需要引用的元素?
  • @bubble-cord 我也可以使用类似 stackoverflow.com/questions/54633690/… 的东西,但在这种情况下,创建一个可重用的组件并让它管理内部的 dom ref 会更有意义
猜你喜欢
  • 2011-04-24
  • 2014-06-06
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 2013-09-06
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多