代码之家  ›  专栏  ›  技术社区  ›  r4id4

Ionic ReactJS Redux在dispatch()后不会重新渲染

  •  0
  • r4id4  · 技术社区  · 4 年前

    我正在将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 与财产 selected false 工作得很好。
    当我触发 toggleCategory() 我明白了 category (从Redux获取) dispatch() )使用新值正确更新,但元素不会重新呈现。

    我已经记录了状态更新和渲染代码

    return (
          // Some React Components
          {
              categories.map(l => {
                console.log("Rendering")
                return ( ... )
            })
         }
         // Some React Components
         )
    

    这是日志,您可以看到初始化已正确呈现(首先 "Updating State" + "Rendering" ),但在触发后 切换类别() 状态从Redux更新 “正在更新状态” 而元素是 “渲染”

    enter image description here

    我错过了什么吗?

    Ps我没有从reducer和action发布代码,因为它有效,因为更新的值达到了我的 类别 状态,并且不想添加熵,但如果你需要,我可以发布它。

    0 回复  |  直到 4 年前
        1
  •  0
  •   HMR    4 年前

    这是一个使用局部状态和重选来记忆具有选定属性的类别的示例。

    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置于状态并更改为选中状态,它会更简单,也可以优化:

    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'));
    <脚本src=“https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js“></script>
    <脚本src=“https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js“></script>
    <脚本src=“https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js“></script>
    
    
    <div id=“root”></div>