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);
还有在页眉中,之后它工作正常。
我已经尝试过其他类似的建议,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);
还有在页眉中,之后它工作正常。