【问题标题】:React.MEMO() fails to work with hooks inside of it (probably useDispatch) within KendoReactReact.MEMO() 无法使用 KendoReact 中的钩子(可能是 useDispatch)
【发布时间】:2021-06-09 19:01:07
【问题描述】:

我在kendo grid 中有一个子过滤器输入组件,我的目标是阻止该组件再次呈现并在输入字段中保存“输入文本”

   <GridColumn
      field="name"
      title="Document Name"
      headerCell={HeaderCell}
      className="tableCell"
      cell={LinkCell}
      filterCell={() =>  <SearchInput className={filtersToggler} /> }
      footerCell={(props) => <FooterCell {...props} colSpan={4} total={total}></FooterCell>}
    />

现在,当我在该组件中添加一些输入时,它会将值传递给名为 word 的状态,并在 500 毫秒后触发 debounce 并将其解析为名为“term”的 redux 状态

const SearchInput = React.memo(() => {
  const [word, setWord] = useState('');

  const dispatch = useDispatch();

  const deb = useCallback(
    debounce((text) => dispatch({ type: 'SET_TERM', term: text }), 1000),
    []
  );

  const handleText = (text) => {
    deb(text);
  };
  return (
    <input
      className="searchInput"
      value={word}
      type="search"
      placeholder="Search.."
      onChange={(e) => {
        handleText(e.target.value)
        setWord(e.target.value);
      }}></input>
  );
});

export default SearchInput;

现在,每当 redux 状态发生变化时,它都会在 kendo 网格内触发 useEffect 并从 API 获取新数据。

  const searchWord = useSelector((state) => state.search.term);
  const classifications = useSelector((state) => state.search.classifications);
  const date = useSelector((state) => state.search.date);

  useEffect(() => {
    const data = searchDocsByName(searchWord, date, classifications);
    data.then((i) => {
      setDocuments(i.data.data);
      setTotal(i.data.data.length);
    });
  }, [searchWord, date, classifications]);

那么问题是什么? SearchInput Componenet 重新渲染,即使它在 React.memo() 内部,并且从分析器中我得到 SearchInput 渲染是因为“挂钩更改”。

我完全被卡住了,我不知道如何处理。

【问题讨论】:

  • 由于 setWord(e.target.value),它会在每次更改时渲染,但可能您的意思是额外渲染?对于您在输入中键入的每个字母,它会呈现多少次?
  • 如果我从 kendo 网格查看文档中的示例,他们会将组件名称传递给 filterCell,而您传递一个将组件返回给 filterCell 的函数。这取决于 GridColumn 的实现。您可以将其更改为 filterCell={SearchInput} 以检查它是否可以摆脱重新渲染
  • 嘿 jelte,要让过滤器单元继承道具,您需要传递一个带有道具参数的函数,但是是的,这就是问题所在。谢谢。

标签: reactjs redux kendo-ui kendo-grid memo


【解决方案1】:

您不必要地使用const [word, setWord] = useState(''); 设置本地状态,setWord 将重新渲染您的组件,因为本地状态已更改。您可以将输入设为uncontrolled component

以下是您可以执行的操作的示例:

const { Provider, useDispatch } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { useCallback } = React;

const initialState = {};
const reducer = (state, { type, term }) => {
  console.log('in reducer', type, term);
  return state;
};
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(
      () => (next) => (action) => next(action)
    )
  )
);
const debounce = (fn, time) => {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), time);
  };
};
const SearchInput = React.memo(function SearchInput() {
  console.log('rendering SearchInput');
  const dispatch = useDispatch();
  const deb = useCallback(
    debounce(
      (text) => dispatch({ type: 'SET_TERM', term: text }),
      1000
    ),
    []
  );
  return (
    <input
      className="searchInput"
      type="search"
      placeholder="Search.."
      onChange={(e) => {
        deb(e.target.value);
      }}
    ></input>
  );
});

const App = () => {
  return <SearchInput />;
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>

<div id="root"></div>

【讨论】:

  • 感谢这个好答案,但实际答案是破解剑道组件的错误。我将函数传递给过滤器单元,而不仅仅是组件。你的意见很有价值,我用额外的状态等纠正了你在这里指出的错误。ty
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 2020-05-03
  • 2021-02-13
  • 1970-01-01
  • 2019-10-12
  • 2019-12-17
  • 1970-01-01
相关资源
最近更新 更多