Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
230 views
in Technique[技术] by (71.8m points)

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

I have tried other similar suggestions, none work therefore I'm posting my own question. So I have a react js app that is using redux. I need to show a columns dropdown using which I can set a table's columns to show or hide. I have a header component and a list component, both are siblings. I'm trying to change the value of columnList in header component, dispatching update action to update in store and on that basis I'm trying to change columns in the list component. My issue at the moment is that my list component is not rerendering when I change visibility of columnList, nor is it triggering the useEffect. However, what's further confusing me is while inspect in chrome is opened, and once I change the columnList value in header component, moving the partition to either increase or decrease the inspect window shows or hides the columns depending on how I set them(This is the only time when they show/hide).

Below is the list component, irrelevant parts and additional column list value have not been included

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>
  );
};

Below is my 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>
  );
};

And finally below is my 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,
         }
      };

and action file

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,
});

Sorry the files are to big, containing other things to be posted completely.

question from:https://stackoverflow.com/questions/65649822/reduxchanging-the-value-in-store-does-not-trigger-my-another-component-using-th

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You were almost there but did are still mutating, you should carefully read and try to understand how to update in an immutable way.

Here is the code that should work:

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,
  };
}

If this didn't work you should check what is getting rendered I don't know what the Table component is but it may not re render when props change because it has a buggy implementation, I know old react bootstrap had some problems.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...