Redux:Changing 存储中的值不会触发我使用相同值的另一个组件

Redux:Changing the value in store does not trigger my another component using the same value

我已经尝试过其他类似的建议,none 有效,因此我发布了我自己的问题。 所以我有一个使用 redux 的 React js 应用程序。我需要显示一个列下拉列表,使用它我可以设置 table 的列来显示或隐藏。 我有一个 header 组件和一个列表组件,它们都是兄弟姐妹。我正在尝试更改 header 组件中 columnList 的值,分派更新操作以在商店中进行更新,并在此基础上尝试更改列表组件中的列。 我目前的问题是,当我更改 columnList 的可见性时,我的列表组件没有重新呈现,也没有触发 useEffect。 然而,让我更加困惑的是,当打开 inspect in chrome 时,一旦我更改了 header 组件中的 columnList 值,移动分区以增加或减少 inspect window 显示或根据我的设置方式隐藏列(这是唯一一次 show/hide)。

以下为列表组件,不包含无关部分和附加列列表值

const columnList=useSelector(selectColumnList,shallowEqual);

var columns = [
    {
      id:1,
      title: "RPA ID",
      dataIndex: "",
      columnVisible:true,
      render: (record) => {
        let id = record.id.toString().padStart(3, "0");
        return `RPA${id}`;
      },
    },]

  useEffect(()=>{
    console.log("triggering dispatch")
    dispatch(updateOpportunityColumns(columns));
  },[])

const renderBody = (props, columns) => {
      return (
        <tr className={props.className}>
          {columns.map((item, idx) => {
            if (item.columnVisible) {
              return props.children[idx]
            }
          })}
        </tr>
      );
    }

    const renderHeader = (props, columns) => {
      return (
        <tr>
          {columns.map((item, idx) => {
            if (item.columnVisible)
              return props.children[idx];
          })}
        </tr>
      );
    }

  return (
    <div>
      <Table
        rowKey="uid"
        onRow={(record, rowIndex) => {
          return {
            onDoubleClick: () => {
              history.push({
                pathname: `${
                  RouteNames.Opportunity.path
                }/RPA${record.id.toString().padStart(3, "0")}`,
                opportunityId: record.id,
              });
            },
          };
        }}
        columns={columnList}
        dataSource={pagedData}
        pagination={{
          total: total,
          defaultPageSize: pageSize,
          current: currentPage,
          onChange: onPageChange,
        }}
        components={{
          header: {
            row: (props) => renderHeader(props, columnList),
          },
          body: {
            row: (props) => renderBody(props, columnList)
          },
        }}
      />
    </div>
  );
};

下面是我的header

var columns=useSelector(selectColumnListIntermediate,shallowEqual)
const [state,setState]=useState();

  function handleDropdownCheckboxClick(i,event){
    event.stopPropagation();
    dispatch(updateOpportunityColumnAtIndex(i));
  }

const menus=Object.entries(columns).map((key,i)=>{
    if(key[1].title){
      return(
        <Menu key={key[0]}>
        <Menu.Item key={key[0]}>
          <Checkbox checked={key[1].columnVisible} onClick={(e)=>{handleDropdownCheckboxClick(i,e)}} >{key[1].title}</Checkbox>
        </Menu.Item>
      </Menu>
  )}})

  const menu = () => {
    return (
      <Menu onClick={""}>
        {menus}
      </Menu>
    )};
  return (
    <div>
      <div style={{ display: "flex", alignItems: "flex-end" }}>
        <Avatar
          style={{ marginRight: "5px" }}
          shape="square"
          size={64}
          src={`${URL}${logoUrl}`}
        />

        <Title style={{ color: "#0AA9F0" }} level={3}>
          {name}
        </Title>
      </div>
      <Divider />

      <div>
        <Button
          className="btn-border"
          onClick={handleClick}
          style={{ width: "300px" }}
          type="primary"
          shape="circle"
          icon={<PlusOutlined />}
        >
          Create Opportunity
        </Button>
        
        
        <Dropdown.Button overlay={menu}>
          Columns
        </Dropdown.Button>

        <div className="userlist">
          <Search
            placeholder="Search"
            allowClear
            onSearch={(value) => onSearch(value)}
            enterButton
          />
        </div>
      </div>
    </div>
  );
};

下面是我的reducer

case UPDATE_COLUMNS_LIST:
{
       return {
        ...state,
        ColumnListIntermediate:payload,
        ColumnList:payload,
      };}

case UPDATE_COLUMN_LIST_AT_INDEX:{
        const newArray = [...state.ColumnList];
        newArray[action.payload].columnVisible = !state.ColumnList[payload].columnVisible
        return { 
          ...state,
          ColumnList:newArray,
          ColumnListIntermediate:newArray,
         }
      };

和操作文件

export const getOpportunityColumns = () => ({
  type: GET_COLUMNS_LIST
});

export const getOpportunityColumnsIntermediate = () => ({
  type: GET_COLUMNS_LIST_INTERMEDIATE
});

export const updateOpportunityColumns = (ColumnValue) => ({
  type: UPDATE_COLUMNS_LIST,
  payload: ColumnValue,
});

export const updateOpportunityColumnAtIndex = (index) => ({
  type: UPDATE_COLUMN_LIST_AT_INDEX,
  payload: index,
});

对不起,文件太大了,还有其他东西要完整发布。

你快到了,但确实还在变异,你应该仔细阅读并尝试理解how to update in an immutable way

下面是应该有效的代码:

case UPDATE_COLUMN_LIST_AT_INDEX: {
  //map state.ColumList to new array
  const newArray = state.ColumnList.map((item, index) =>
    index === action.payload
      ? //toggle columVisible if index is action payload
        { ...item, columnVisible: !item.columnVisible }
      : //return item unchanged, index is not action.payload
        item
  );
  return {
    ...state,
    ColumnList: newArray,
    ColumnListIntermediate: newArray,
  };
}

如果这不起作用,你应该检查正在渲染的内容我不知道 Table 组件是什么,但当道具改变时它可能不会重新渲染,因为它有一个错误的实现,我知道旧反应 bootstrap 有一些问题。

非常感谢您的帮助,尽管从这里开始我只是从列表组件中删除了“shallowEqual”,

const columnList=useSelector(selectColumnList,shallowEqual);

const columnList=useSelector(selectColumnList);

还有在页眉中,之后它工作正常。