reactjs - Ionic ReactJS-Redux 在 dispatch() 后不会重新渲染
问题描述
我将 Ionic 与 ReacJS 和 Redux 一起使用,我遇到了一个问题,即在第一次加载后元素没有重新渲染,即使状态发生了变化。
这是代码
var categoriesTemplate = [{name:'Science', selected:false}, ... ]
const categories = useSelector((state: any) => {
console.log("Updating State")
let cat = state.categories
for (let c of cat) {
for (var category of categoriesTemplate) {
if (category.name === c) {
category.selected = true
}
}
}
return categoriesTemplate
})
const dispatch = useDispatch()
const toggleCategory = (categorySelected: string) => {
console.log("Toggle + Dispatch")
for (var category of categories) {
if (category.name === categorySelected) {
category.selected = !category.selected
}
}
let newCategories = categories.filter(c => { return c.selected }).map(c => c.name)
dispatch(setCategoriesState(newCategories))
}
第一次运行加载所有categoriesTemplate
with 属性selected
以false
正常工作。
当我触发时,toggleCategory()
我看到category
(从 Redux after 获取dispatch()
)已正确更新为新值,但元素没有重新渲染。
我已经记录了状态更新和渲染代码
return (
// Some React Components
{
categories.map(l => {
console.log("Rendering")
return ( ... )
})
}
// Some React Components
)
这是日志,如您所见,初始化正确呈现(第一个"Updating State"
+ "Rendering"
),但是在toggleCategory()
状态触发器从 Redux 更新之后,"Updating State"
而元素没有 "Rendering"
我错过了什么吗?
Ps 我没有从 reducer 和 action 发布代码,因为它可以工作,因为更新的值达到了我的category
状态,并且不想添加熵,但如果你需要我可以发布它。
解决方案
这是一个使用本地状态和重新选择来记忆具有选定属性的类别的示例。
const { createSelector } = Reselect;
const categoriesTemplate = [
{ name: 'Science', selected: false },
{ name: 'Technology', selected: false },
];
//selectors
const selectCategoriesWithSelected = createSelector(
[
(allCategories) => allCategories,
(_, selectedNames) => selectedNames,
],
(allCategories, selectedNames) =>
allCategories.map((category) => ({
...category,
selected: selectedNames.includes(category.name),
}))
);
//Category is a pure component, does not realy matter in this case
// all category items are re created when you toggle one
// selected, that's just the way you implemented it and can be
// implemented better
const Cateory = React.memo(function Category({
toggleCategory,
category,
}) {
return (
<li>
<a
onClick={(e) => {
e.preventDefault();
toggleCategory(category.name);
}}
href="/"
>
{category.name}{' '}
{category.selected ? 'selected' : ''}
</a>
</li>
);
});
function App() {
const [
selectedCategoriesNames,
setSelectedCategoriesNames,
] = React.useState(() =>
categoriesTemplate
.filter(({ selected }) => selected)
.map(({ name }) => name)
);
const toggleCategory = React.useCallback(
(categoryName) =>
//this is the action and reducer combined because
// we are using local state
setSelectedCategoriesNames(//add or remove category name to selected list
(selectedCategoriesNames) =>
selectedCategoriesNames.includes(categoryName)
? selectedCategoriesNames.filter(
(c) => c !== categoryName
)
: selectedCategoriesNames.concat(categoryName)
),
[]
);
const categoriesWithSelected = selectCategoriesWithSelected(
categoriesTemplate,
selectedCategoriesNames
);
return (
<ul>
{categoriesWithSelected.map((category) => (
<Cateory
key={category.name}
category={category}
toggleCategory={toggleCategory}
/>
))}
</ul>
);
}
ReactDOM.render(<App />, 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/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>
如果您只是将 categoriesTemplate 置于 state 并更改 selected 它会更简单并且可以优化:
const Cateory = React.memo(function Category({
toggleCategory,
category,
}) {
console.log('rendering', category.name);
return (
<li>
<a
onClick={(e) => {
e.preventDefault();
toggleCategory(category.name);
}}
href="/"
>
{category.name}{' '}
{category.selected ? 'selected' : ''}
</a>
</li>
);
});
function App() {
const [categories, setCategories] = React.useState([
{ name: 'Science', selected: false },
{ name: 'Technology', selected: false },
]);
const toggleCategory = React.useCallback(
(categoryName) =>
//this is the action and reducer combined because
// we are using local state
setCategories((categories) =>
categories.map((c) =>
c.name === categoryName
? { ...c, selected: !c.selected }
: c
)
),
[]
);
return (
<ul>
{categories.map((category) => (
<Cateory
key={category.name}
category={category}
toggleCategory={toggleCategory}
/>
))}
</ul>
);
}
ReactDOM.render(<App />, 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/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>
推荐阅读
- android - Firebase 设置问题
- python - 从所有具有相同键的字典列表中,大多数pythonic方式从所有字典中获取相同键的值
- android - Android:静默更新应用程序的所有方式
- java - 使用 NetSuite SOAP API 以编程方式编辑供应商账单的批准状态
- javascript - 过滤映射后如何在对象中创建数组?
- asp.net-core - 使用 MEL ILogger 时如何解构动态
作为门面? - jquery - 如何在jquery中编写泛型方法
- angular - 使用 FormArray 动态添加 FormControl 也会提交我的表单
- python - 查找数据框中每一行的出现次数
- node.js - Prisma createCart 函数无法在查询字段上返回 userId