React.MEMO() 无法在 KendoReact 中使用其内部的钩子(可能是 useDispatch)
React.MEMO() fails to work with hooks inside of it (probably useDispatch) within KendoReact
我在 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 毫秒后触发去抖并将其解析为名为“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 呈现,因为“挂钩更改”。
我完全卡住了,我不知道如何处理。
您不必要地使用 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>
我在 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 毫秒后触发去抖并将其解析为名为“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 呈现,因为“挂钩更改”。
我完全卡住了,我不知道如何处理。
您不必要地使用 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>